Transition, Teleport and KeepAlive

Vue · Advanced · 13 min

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; use onActivated/onDeactivated

Watch out for

  • Wrapping several root elements in <Transition>; it animates one element, use <TransitionGroup> for lists.

Check yourself

  1. A modal inside a card with overflow: hidden gets clipped. Which built-in fixes it while keeping the modal's props and events working?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: vuejs.org/guide/built-ins/teleport.html

Builds on

Unlocks

Nothing builds on this yet.