Dynamic components in Vue.js
What are Dynamic Components?
Dynamic components allow you to switch between different components at the same mount point using the built-in <component> element with the :is attribute.
Basic Usage
vue
<script setup>
import { ref, shallowRef } from 'vue'
import TabHome from './TabHome.vue'
import TabSettings from './TabSettings.vue'
import TabProfile from './TabProfile.vue'
const tabs = { home: TabHome, settings: TabSettings, profile: TabProfile }
const currentTab = shallowRef(TabHome)
</script>
<template>
<div class="tabs">
<button
v-for="(comp, name) in tabs"
:key="name"
:class="{ active: currentTab === comp }"
@click="currentTab = comp"
>
{{ name }}
</button>
</div>
<component :is="currentTab" />
</template>With String Names
vue
<script setup>
import { ref } from 'vue'
// Components must be registered globally or locally
const currentView = ref('HomeView')
</script>
<template>
<component :is="currentView" />
</template>With KeepAlive
Preserve state when switching between dynamic components:
vue
<template>
<KeepAlive>
<component :is="currentTab" />
</KeepAlive>
</template>Passing Props and Events
vue
<template>
<component
:is="currentComponent"
:title="title"
:data="componentData"
@submit="handleSubmit"
@close="handleClose"
/>
</template>Practical Example: Form Builder
vue
<script setup>
import { shallowRef } from 'vue'
import TextInput from './TextInput.vue'
import SelectInput from './SelectInput.vue'
import CheckboxInput from './CheckboxInput.vue'
import TextareaInput from './TextareaInput.vue'
const fieldComponents: Record<string, any> = {
text: TextInput,
select: SelectInput,
checkbox: CheckboxInput,
textarea: TextareaInput,
}
const formFields = [
{ type: 'text', name: 'name', label: 'Name' },
{ type: 'select', name: 'role', label: 'Role', options: ['Admin', 'User'] },
{ type: 'checkbox', name: 'active', label: 'Active' },
{ type: 'textarea', name: 'bio', label: 'Bio' },
]
</script>
<template>
<form>
<div v-for="field in formFields" :key="field.name">
<component
:is="fieldComponents[field.type]"
:label="field.label"
:name="field.name"
v-bind="field"
/>
</div>
</form>
</template>HTML Elements as Dynamic Components
vue
<script setup>
const tag = ref('h1')
</script>
<template>
<!-- Renders as <h1>, <h2>, <p>, etc. -->
<component :is="tag">Dynamic Heading</component>
</template>shallowRef for Components
typescript
// ✅ Use shallowRef for component references
const currentComponent = shallowRef(TabHome)
// ❌ Don't use ref — it makes the component deeply reactive (unnecessary)
const currentComponent = ref(TabHome) // Unnecessary deep reactivityImportant:
Dynamic components with <component :is="..."> let you switch components at the same mount point. Use shallowRef to store component references. Combine with <KeepAlive> to preserve state. Common use cases: tabs, form builders, plugin systems, and rendering different components based on data.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.