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.

🧠 Test Your Knowledge

What attribute is used to specify which component to render dynamically?