Vue docs, chapter by chapter

Built-in components

Transition and TransitionGroup classes, hooks and modes, KeepAlive include/exclude/max, Teleport targets and defer, and Suspense's async dependencies, events and nesting rules.

Five components ship with Vue and each has a small API with precise semantics: six transition classes, three KeepAlive props, one Teleport target rule, two Suspense slots. These are the facts to have cold.

Know — Transition

  • Triggers: v-if, v-show, <component :is> switching, or a change of the key attribute. Wraps one element or component.
  • Six classes: v-enter-from, v-enter-active, v-enter-to, v-leave-from, v-leave-active, v-leave-to; with name="fade" the prefix becomes fade-. *-active classes are where transition/animation declarations go.
  • CSS animations work the same, except Vue waits for animationend; when an element has both a transition and an animation, set type="transition" | "animation" to say which one to wait for.
  • Custom classes (enter-active-class, leave-active-class, …) integrate libraries such as Animate.css. duration (number or { enter, leave }) handles nested transitions whose inner durations Vue cannot detect.
  • JavaScript hooks: @before-enter, @enter(el, done), @after-enter, @enter-cancelled, @before-leave, @leave(el, done), @after-leave, @leave-cancelled; with :css="false" Vue skips CSS detection and you must call done.
  • appear animates the initial render. mode="out-in" | "in-out" orders transitions between elements. Dynamic transitions bind :name. Reusable transitions wrap <Transition> in a component with a slot. Performance advice: animate transform and opacity.

Know — TransitionGroup

  • Animates lists: no wrapper by default, tag renders one; modes are not available; every child needs a unique key; classes apply to the children.
  • Move transitions: the v-move class (or move-class) animates position changes using FLIP; set position: absolute on leaving items so the rest can move smoothly.
  • Staggering uses data-index and JavaScript hooks (the guide uses GSAP).

Know — KeepAlive

  • Caches component instances when switching dynamically (<component :is>), preserving state instead of destroying them.
  • include / exclude: comma-delimited string, RegExp, or array, matched against the component's name (inferred from the SFC filename since 3.2.34 when using <script setup>). max limits cached instances with an LRU policy.
  • Lifecycle: onActivated / onDeactivated; they also fire on initial mount and on unmount, so they can replace mount/unmount hooks for cached components.

Know — Teleport

  • to is a CSS selector or an element; the target must exist when the Teleport mounts, unless defer (3.5+) is used, which waits until the rest of the application has mounted (the target must still be in the same render tick or earlier).
  • disabled renders in place (useful for mobile layouts). Multiple Teleports to the same target append in order.
  • The component tree is unchanged: props, events, provide/inject keep working. SSR requires the target to be handled by the framework (Nuxt does this for body).

Know — Suspense

  • Still marked experimental. Two kinds of async dependencies: components with an async setup() (top-level await in <script setup>) and async components (which then ignore their own loading state).
  • Slots: #default and #fallback; the fallback is shown until every dependency in the default slot resolves; on subsequent changes a timeout prop controls how long the old content stays before the fallback shows.
  • Events: pending, resolve, fallback. Errors are not handled by Suspense; use onErrorCaptured in a parent or errorCaptured in the app.
  • Combining: recommended nesting RouterView → Transition → KeepAlive → Suspense → component. Nested Suspense (3.3+) uses the suspensible prop on the inner one so its pending state is handled by the parent.

How it works

app/components/Docs/BuiltIns.vue
<script setup lang="ts">
const show = ref(true)
const items = ref([1, 2, 3])
const tab = ref<'A' | 'B'>('A')
const dialog = ref(false)
const tabs = { A: defineAsyncComponent(() => import('./TabA.vue')), B: defineAsyncComponent(() => import('./TabB.vue')) }
</script>

<template>
  <!-- CSS transition, out-in between two elements keyed by content -->
  <Transition name="fade" mode="out-in" appear>
    <p v-if="show" key="on">On</p>
    <p v-else key="off">Off</p>
  </Transition>

  <!-- List with move transitions; each child keyed -->
  <TransitionGroup tag="ul" name="list">
    <li v-for="n in items" :key="n">{{ n }}</li>
  </TransitionGroup>

  <!-- Cached tabs, at most two instances, only names matching /^Tab/ -->
  <KeepAlive :include="/^Tab/" :max="2">
    <Suspense :timeout="150">
      <component :is="tabs[tab]" />
      <template #fallback><p>Loading…</p></template>
    </Suspense>
  </KeepAlive>

  <!-- Teleport with defer: the #modals target may render later in this tick -->
  <Teleport to="#modals" defer :disabled="!dialog">
    <div v-if="dialog" role="dialog">Hello</div>
  </Teleport>
</template>

<style scoped>
.fade-enter-active, .fade-leave-active { transition: opacity 0.2s ease; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
.list-move, .list-enter-active, .list-leave-active { transition: all 0.3s ease; }
.list-enter-from, .list-leave-to { opacity: 0; transform: translateX(20px); }
.list-leave-active { position: absolute; } /* lets the remaining items move smoothly */
</style>
Gotcha· Transitions between same-tag elements

Two <p> elements toggled with v-if/v-else are patched in place, so no transition runs. Give them distinct keys so Vue treats them as different elements; the guide calls this out explicitly.

Exercise

Exercise
  • Write a fade transition, then add a CSS animation on the same element and observe which end event Vue waits for; fix it with type.
  • Put two components in KeepAlive with max="1" and log onActivated/onDeactivated while switching three times.
  • Teleport into a target rendered after the Teleport in the same component, first without and then with defer.

Be able to say

Be able to say· Explain the Transition classes and when JavaScript hooks are needed.

"Vue toggles six classes: enter-from, enter-active and enter-to when an element appears, and the leave- trio when it goes, each prefixed with the transition's name. The active classes carry the transition or animation declaration; Vue listens for transitionend or animationend to know when to remove them, and type decides which when both exist, duration overrides detection for nested transitions. JavaScript hooks from before-enter to leave-cancelled are for animation libraries: with :css=\"false\" Vue skips CSS detection entirely and waits for the done callback I call from enter and leave."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.