Vue Dynamic Components
Switch between components dynamically at runtime
🔀 What are Dynamic Components?
Dynamic components let you switch between different components at runtime using the special component element. Perfect for tabs, wizards, and conditional interfaces where you need to display different components based on user interaction or application state.
<component :is="currentComponent"></component>
<script setup>
import { ref } from 'vue'
const currentComponent = ref('HomeView')
</script>
Dynamic Component Features
Component Switching
Change components on the fly
<component
:is="activeTab"
/>
Keep-Alive
Preserve component state
<keep-alive>
<component :is="view" />
</keep-alive>
Tab Interfaces
Perfect for tabbed content
<button @click="tab='home'">
Home
</button>
Conditional Rendering
Show components based on logic
<component
:is="userRole + 'View'"
/>
🔹 Basic Dynamic Component
Switch between components using the :is attribute:
🔸 Component Files
<!-- Home.vue -->
<template>
<div><h2>Home Page</h2></div>
</template>
<!-- About.vue -->
<template>
<div><h2>About Page</h2></div>
</template>
<!-- Contact.vue -->
<template>
<div><h2>Contact Page</h2></div>
</template>
🔸 Parent Component
<template>
<div>
<button @click="currentView = 'Home'">Home</button>
<button @click="currentView = 'About'">About</button>
<button @click="currentView = 'Contact'">Contact</button>
<component :is="currentView"></component>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Home from './Home.vue'
import About from './About.vue'
import Contact from './Contact.vue'
const currentView = ref('Home')
</script>
Output:
Home Page
🔹 Tab Interface with Dynamic Components
Create a tabbed interface:
<template>
<div class="tabs">
<div class="tab-buttons">
<button
v-for="tab in tabs"
:key="tab"
@click="activeTab = tab"
:class="{ active: activeTab === tab }"
>
{{ tab }}
</button>
</div>
<div class="tab-content">
<component :is="activeTab"></component>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Profile from './Profile.vue'
import Settings from './Settings.vue'
import Messages from './Messages.vue'
const tabs = ['Profile', 'Settings', 'Messages']
const activeTab = ref('Profile')
</script>
<style scoped>
.tab-buttons button.active {
background: #42b883;
color: white;
}
</style>
🔹 Keep-Alive for State Preservation
Preserve component state when switching:
<template>
<div>
<button @click="view = 'FormA'">Form A</button>
<button @click="view = 'FormB'">Form B</button>
<!-- Without keep-alive: state is lost -->
<component :is="view"></component>
<!-- With keep-alive: state is preserved -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
</div>
</template>
<script setup>
import { ref } from 'vue'
const view = ref('FormA')
</script>
Note: keep-alive caches inactive components, preserving their state and avoiding re-renders.
🔹 Include/Exclude with Keep-Alive
Control which components are cached:
<template>
<div>
<!-- Cache only specific components -->
<keep-alive include="Profile,Settings">
<component :is="currentView"></component>
</keep-alive>
<!-- Exclude specific components from cache -->
<keep-alive exclude="Login">
<component :is="currentView"></component>
</keep-alive>
<!-- Limit number of cached instances -->
<keep-alive :max="3">
<component :is="currentView"></component>
</keep-alive>
</div>
</template>
🔹 Dynamic Component with Props
Pass props to dynamic components:
<template>
<div>
<component
:is="currentComponent"
:title="pageTitle"
:data="pageData"
@update="handleUpdate"
></component>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Dashboard from './Dashboard.vue'
import Reports from './Reports.vue'
const currentComponent = ref('Dashboard')
const pageTitle = ref('My Dashboard')
const pageData = ref({ users: 100, sales: 5000 })
const handleUpdate = (data) => {
console.log('Updated:', data)
}
</script>
🔹 Async Dynamic Components
Load components dynamically with lazy loading:
<template>
<div>
<button @click="loadComponent('Heavy')">
Load Heavy Component
</button>
<Suspense>
<template #default>
<component :is="asyncComponent"></component>
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</div>
</template>
<script setup>
import { ref, defineAsyncComponent } from 'vue'
const asyncComponent = ref(null)
const loadComponent = (name) => {
asyncComponent.value = defineAsyncComponent(() =>
import(`./components/${name}.vue`)
)
}
</script>
🔹 Lifecycle Hooks with Dynamic Components
Handle component activation and deactivation:
<!-- Child Component -->
<template>
<div>{{ message }}</div>
</template>
<script setup>
import { ref, onActivated, onDeactivated } from 'vue'
const message = ref('Component Active')
onActivated(() => {
console.log('Component activated')
// Refresh data, resume timers, etc.
})
onDeactivated(() => {
console.log('Component deactivated')
// Pause timers, save state, etc.
})
</script>
Tip: Use onActivated and onDeactivated hooks with keep-alive to manage component lifecycle.