Dynamic & Async Components
Switch between components dynamically with <component :is>, and load large components lazily.
The <component :is> Element
<component :is="..."> renders whichever component (or element) its is attribute currently points to, letting you switch which component is displayed based on state.
<script setup>import { ref } from 'vue';import HomeTab from './HomeTab.vue';import ProfileTab from './ProfileTab.vue';
const currentTab = ref(HomeTab);</script>
<template> <component :is="currentTab" /> <button @click="currentTab = ProfileTab">Go to Profile</button></template>A Tabbed Interface Example
A common use is switching by name, looked up from a map of tab keys to components.
<script setup>import { ref, shallowRef } from 'vue';import HomeTab from './HomeTab.vue';import ProfileTab from './ProfileTab.vue';
const tabs = { home: HomeTab, profile: ProfileTab };const activeTabKey = ref('home');</script>
<template> <button @click="activeTabKey = 'home'">Home</button> <button @click="activeTabKey = 'profile'">Profile</button> <component :is="tabs[activeTabKey]" /></template>When a ref holds a component definition (not plain data), shallowRef avoids Vue trying to deeply make the component object itself reactive, which is unnecessary overhead.
Async Components
defineAsyncComponent wraps a dynamic import() so a large or rarely-used component only loads when it's actually rendered — reducing your initial bundle size.
<script setup>import { defineAsyncComponent } from 'vue';
const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue'));</script>
<template> <Suspense> <HeavyChart /> <template #fallback> <p>Loading chart…</p> </template> </Suspense></template>FAQs
Yes — passing a string like "h1" or "section" renders that native element, which is handy for polymorphic components.
By default, no — the previous component fully unmounts. Wrap it in <KeepAlive> if you want to preserve state across switches.
Summary
<component :is> switches which component renders based on state, and defineAsyncComponent defers loading a component's code until it's actually needed. Next, you'll learn provide/inject for passing data through many layers of nesting at once.