Render a Different Component Based on State
Dynamic Components & component :is
The built-in component element with :is swaps which component renders at a spot. Combine with KeepAlive to cache state across switches.
What you'll learn
- Switch components with :is
- Use it for tabs and wizards
- Combine with KeepAlive to preserve state
Sometimes you want to render different components in the same spot — tab panels, wizard steps, dashboard widgets. Vue’s built-in component element with :is handles this without a giant v-if chain.
Switching by Reference
Import each component and store the active one in a ref. The :is attribute accepts the component itself.
<script setup lang="ts">
import { shallowRef } from 'vue'
import Profile from './Profile.vue'
import Settings from './Settings.vue'
const tabs = { Profile, Settings }
const current = shallowRef<keyof typeof tabs>('Profile')
</script>
<template>
<button @click="current = 'Profile'">Profile</button>
<button @click="current = 'Settings'">Settings</button>
<component :is="tabs[current]" />
</template> Use shallowRef for the active component reference — it avoids Vue trying to make the component definition reactive.
Passing Props and Listeners
The dynamic component accepts props and events just like a static one:
<component :is="tabs[current]" :user="user" @save="onSave" /> KeepAlive
By default, switching unmounts the previous component and remounts the next one — local state is wiped. Wrap with KeepAlive to cache instances and preserve state.
<KeepAlive>
<component :is="tabs[current]" />
</KeepAlive> KeepAlive accepts include / exclude / max props to control caching:
<KeepAlive :include="['Profile']" :max="5">
<component :is="tabs[current]" />
</KeepAlive> Cached components receive activated / deactivated lifecycle hooks instead of mounted / unmounted on each switch.
Template Refs →