These built-ins solve common UI problems (animations, modals, preserving tab state) that are tricky to hand-roll.
Vue ships several built-in components.
`<Transition>` animates a single element or component that is inserted or removed by v-if, v-show, a dynamic component or a key change. It adds classes at the right moments: with name="fade" you style fade-enter-from, fade-enter-active, fade-leave-to and fade-leave-active. mode="out-in" waits for the old element to leave before the new one enters. JavaScript hooks (@enter, @leave) let you use an animation library. `<TransitionGroup>` animates items in a v-for list, including moves via the *-move class; items need keys.
`<Teleport to="body">` renders its content elsewhere in the DOM while keeping it logically inside the component (props, events and provide/inject still work). Use it for modals, toasts and tooltips that must escape overflow: hidden or z-index stacking. :disabled keeps the content in place, and Vue 3.5's defer prop lets the target be rendered later in the same tick.
`<KeepAlive>` caches component instances instead of destroying them when they are switched out, typically around <component :is="tab"> or <RouterView>'s slot. State and scroll positions survive tab switches. Limit it with include, exclude and max. Cached components get onActivated and onDeactivated hooks instead of mount/unmount on each switch.
`<Suspense>` coordinates async components and async setup; it is still marked experimental.
Example
<script setup>
import { ref, shallowRef } from 'vue'
import TabA from './TabA.vue'
import TabB from './TabB.vue'
const open = ref(false), tab = shallowRef(TabA)
</script>
<template>
<button @click="tab = tab === TabA ? TabB : TabA">Switch tab</button>
<KeepAlive :max="5"><component :is="tab" /></KeepAlive> <!-- state survives -->
<button @click="open = true">Open modal</button>
<Teleport to="body">
<Transition name="fade">
<div v-if="open" class="modal" @click.self="open = false">Hello</div>
</Transition>
</Teleport>
</template>
<style>
.fade-enter-active, .fade-leave-active { transition: opacity 0.2s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }</style>Remember
<Transition name="x">adds x-enter-from / x-leave-to etc. classes around v-if/v-show<Teleport to="body">moves DOM output but keeps component relationships<KeepAlive>caches switched-out components; useonActivated/onDeactivated
Watch out for
- Wrapping several root elements in
<Transition>; it animates one element, use<TransitionGroup>for lists.