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.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author