In Vue 3, which six CSS classes does `<Transition>` apply to an entering and a leaving element, and when is each one added and removed?
answer
- from, active, to — twice
- prefix comes from the name prop
- from swapped for to a frame later
- active spans the whole phase
basics
~20 sVue 3's Transition adds v-enter-from, v-enter-active and v-enter-to on insert, and v-leave-from, v-leave-active and v-leave-to on removal. The from class is swapped for the to class a frame later; the active class lasts the whole phase.
solid answer
~40 s`<Transition>` animates one element or component as `v-if`, `v-show` or a changed `key` inserts or removes it. On enter, Vue adds `v-enter-from` and `v-enter-active` before insertion, then on the next frame swaps `v-enter-from` for `v-enter-to`; `-active` and `-to` come off when the CSS transition or animation ends. Leave mirrors it: `v-leave-from` and `v-leave-active` go on as soon as the removal starts, `v-leave-from` is swapped for `v-leave-to` a frame later, and the element is removed when the leave finishes. The `transition` declaration belongs on `-active`; `-enter-from` and `-leave-to` hold the hidden state. A `name` prop replaces the `v` prefix, so `name="toast"` gives `.toast-enter-from` and the rest.
code
vue · 29 lines<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
function notify() {
visible.value = true
setTimeout(() => (visible.value = false), 3000)
}
</script>
<template>
<button @click="notify">Save</button>
<Transition name="toast">
<p v-if="visible" class="toast" role="status">Saved</p>
</Transition>
</template>
<style>
.toast-enter-active,
.toast-leave-active {
transition: opacity 200ms ease, transform 200ms ease;
}
.toast-enter-from,
.toast-leave-to {
opacity: 0;
transform: translateY(8px);
}
</style>go deeper
Recite the six classes in order and say which two you actually style: the active pair for timing, and enter-from with leave-to for the hidden state.
Explain the one-frame swap from -from to -to and why it is needed, and that the leaving node stays in the DOM until its leave ends.
Show you can debug a transition that silently does nothing: a Vue 2 class name, a transition declared on the wrong class, or a missing appear on first render.
Frame class-based transitions as a styling contract a design system can own: shared named transitions with agreed durations, rather than per-component ad hoc CSS.
## What `<Transition>` is for `<Transition>` is a built-in Vue 3 component that wraps **one** element or component and animates it when it is **inserted** into or **removed** from the DOM. It does not animate anything by itself: it adds and removes CSS classes at precise moments, and your stylesheet decides what those classes look like. Three things make its child enter or leave: - a `v-if` (or `v-else-if` / `v-else`) branch appearing or disappearing; - a `v-show` toggling `display`; - the child's `key` changing, which makes Vue replace the element instead of patching it. Because built-in components are available in every template without registration, you write `<Transition>` directly; in a render function you import `Transition` from `vue`. ## The enter phase, step by step When the child is inserted, Vue walks through these steps: 1. **Before insertion** it adds `v-enter-from` (the starting state) and `v-enter-active` (the class that carries the `transition` declaration) to the element. 2. It inserts the element, so the browser renders it once in the starting state. 3. **On the next frame** it removes `v-enter-from` and adds `v-enter-to`. The styled properties now change, and the transition declared on `-active` animates that change. 4. **When the CSS transition or animation ends**, it removes `v-enter-active` and `v-enter-to`. The element is left with only its own classes. The frame delay in step 3 is the whole trick: if the starting and ending states were applied in the same frame, the browser would never paint the start and there would be nothing to animate from. ## The leave phase Leave is the mirror image, with one difference — the element is still in the DOM and must stay there until the animation is over: 1. As soon as the removal is triggered, Vue adds `v-leave-from` and `v-leave-active`. 2. On the next frame it removes `v-leave-from` and adds `v-leave-to`. 3. When the transition or animation ends, it removes the leave classes **and then removes the element** from the DOM. That is why a leave animation can play at all: `v-if` going false does not delete the node immediately when a still-mounted `<Transition>` wraps it; the node is detached only after the leave finishes. ## Where each rule goes | Class | Added | Removed | Typical content | |---|---|---|---| | `v-enter-from` | before insertion | next frame | hidden state: `opacity: 0`, an offset `transform` | | `v-enter-active` | before insertion | when enter ends | `transition: opacity 200ms ease` | | `v-enter-to` | next frame | when enter ends | usually nothing; the resting style | | `v-leave-from` | when leave starts | next frame | usually nothing; the resting style | | `v-leave-active` | when leave starts | when leave ends | `transition: opacity 150ms ease-in` | | `v-leave-to` | next frame | when leave ends | hidden state again | Most stylesheets therefore write only two rules: `-enter-active, -leave-active` for the timing and `-enter-from, -leave-to` for the hidden state. Putting the `transition` declaration on `-enter-from` is a classic mistake: that class is gone by the time the properties change, so there is no transition in effect when the change happens. ## Naming: the `name` prop and custom class props - `name="toast"` swaps the `v` prefix, producing `toast-enter-from`, `toast-enter-active` and so on. Use it whenever a page has more than one kind of transition. - The props `enter-from-class`, `enter-active-class`, `enter-to-class`, `leave-from-class`, `leave-active-class` and `leave-to-class` replace the generated name for a single stage. They exist mainly to plug in class names from a CSS animation library. ## `appear` and the Vue 2 rename By default the child is **not** animated on the initial render of the `<Transition>`; only later inserts and removals are. The `appear` prop turns the initial render into an enter as well, reusing the enter classes unless you pass `appear-from-class`, `appear-active-class` or `appear-to-class`. If you read Vue 2 code, the starting classes were called `v-enter` and `v-leave`. Vue 3 renamed them to `v-enter-from` and `v-leave-from` so both phases share the same `from / active / to` shape. A Vue 3 app styling `.fade-enter` gets no starting state and the fade-in silently disappears. ## A quick way to remember it - **from** is where the element starts (enter) or the resting state it leaves from (leave); - **active** is the whole duration and holds the timing; - **to** is where it ends. Enter goes hidden → visible; leave goes visible → hidden. Everything else is the frame-by-frame bookkeeping Vue does so that the browser sees a real change of style to animate.
- Why do you usually not write rules for `v-enter-to` and `v-leave-from`?They describe the element's normal resting state. When `-enter-from` comes off and nothing else overrides opacity or transform, the element returns to its ordinary styles, and the `transition` on `-active` animates that change. You write `-enter-to` or `-leave-from` only when the start or end point is not the resting style, for example animating to a scale other than the element's default.
- What does the `appear` prop change, and which classes does it use?Without `appear`, `<Transition>` does not animate its child on its own initial render; only later inserts and removals animate. With `appear`, the child also animates when the `<Transition>` first mounts. By default that reuses the enter classes and enter hooks; `appear-from-class`, `appear-active-class`, `appear-to-class` and the `@appear` family of events override them.
- How do you use class names from a CSS animation library instead of the generated ones?Pass the custom class props — `enter-from-class`, `enter-active-class`, `enter-to-class`, `leave-from-class`, `leave-active-class`, `leave-to-class` (camelCase in render functions). Each replaces the generated name for that stage only, so `enter-active-class="animate-in"` adds that class for the whole enter phase while the other stages keep their `name`-based defaults.
saying these in an interview costs you the question
- The enter classes stay on the element after the enter has finished.
- In Vue 3 the enter starting class is still called v-enter.
- The -from and -to classes are added at the same moment.
- Putting the transition declaration on v-enter-from animates the enter phase.
- Transition animates its child on the first render without any extra prop.
- The leaving element is removed immediately and a clone is animated instead.