Dynamic Components & component :is

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.

4 min read Level 2/5 #vue#components#dynamic
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 →