How to create dynamic components in Vue
Creating dynamic components in Vue allows you to render different components conditionally at runtime, enabling flexible interfaces that adapt based on data, user interactions, or application state. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented dynamic components in thousands of Vue applications for dashboard widgets, form fields, and content management systems where component types are determined dynamically. From my expertise, the most effective approach is using the built-in component element with the is attribute and proper component registration. This method provides flexible component rendering with clean conditional logic and efficient component switching.
Use the component element with is attribute to dynamically render different components based on reactive data.
<template>
<div>
<h3>Dynamic Component Demo</h3>
<!-- Component selector -->
<div class="component-selector">
<button
v-for="comp in availableComponents"
:key="comp.name"
@click="currentComponent = comp.name"
:class="{ active: currentComponent === comp.name }"
>
{{ comp.label }}
</button>
</div>
<!-- Dynamic component rendering -->
<div class="dynamic-component-wrapper">
<component
:is="currentComponent"
:data="componentData"
@update="handleComponentUpdate"
/>
</div>
<!-- Dynamic component with keep-alive -->
<div class="preserved-component">
<keep-alive>
<component
:is="preservedComponent"
:settings="preservedSettings"
/>
</keep-alive>
</div>
<!-- Dynamic component with fallback -->
<div class="fallback-component">
<component
:is="componentExists(selectedWidget) ? selectedWidget : 'DefaultWidget'"
:config="widgetConfig"
/>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import UserCard from './components/UserCard.vue'
import ProductCard from './components/ProductCard.vue'
import StatCard from './components/StatCard.vue'
import DefaultWidget from './components/DefaultWidget.vue'
const currentComponent = ref('UserCard')
const preservedComponent = ref('ProductCard')
const selectedWidget = ref('StatCard')
const availableComponents = ref([
{ name: 'UserCard', label: 'User Profile' },
{ name: 'ProductCard', label: 'Product Info' },
{ name: 'StatCard', label: 'Statistics' }
])
const componentData = computed(() => {
switch (currentComponent.value) {
case 'UserCard':
return { name: 'John Doe', email: '[email protected]' }
case 'ProductCard':
return { title: 'Laptop', price: 999, stock: 5 }
case 'StatCard':
return { value: 1250, label: 'Sales', trend: 'up' }
default:
return {}
}
})
const preservedSettings = ref({
theme: 'dark',
showDetails: true
})
const widgetConfig = ref({
color: 'primary',
size: 'large'
})
const componentExists = (componentName) => {
return ['UserCard', 'ProductCard', 'StatCard'].includes(componentName)
}
const handleComponentUpdate = (data) => {
console.log('Component updated:', data)
}
</script>
<style scoped>
.component-selector button {
margin-right: 10px
padding: 8px 16px
border: 1px solid #ccc
background: white
cursor: pointer
}
.component-selector button.active {
background: #007bff
color: white
}
.dynamic-component-wrapper {
margin: 20px 0
padding: 20px
border: 1px solid #eee
}
</style>
The component element with is attribute dynamically renders components based on the provided component name. Use keep-alive to preserve component state when switching between components. Implement fallback logic to handle cases where the specified component doesn’t exist. Pass props and listen to events normally as the dynamic component behaves like any other component.
Best Practice Note:
This is the same dynamic component pattern we use in CoreUI Vue applications for dashboard widgets, form builders, and content management systems where component types are determined at runtime.