Why a conditional alert vanishes before its leave animation
Vue needs a moment between removal and disappearance
A conditional alert normally disappears as soon as its branch is removed. Wrapping that one element in Vue's Transition component gives Vue a chance to keep the old DOM node briefly while CSS animates it out. Vue applies lifecycle classes around insertion and removal; your stylesheet defines visual states and durations. The component does not invent an animation by itself. If the element has no matching CSS transition or animation, it will still appear to change immediately.
Use a named Transition around one conditional element, such as a success paragraph controlled by a ref. The default class prefix is v-. Supplying a name such as notice changes it to notice-. Entering applies the enter-from and enter-active classes at the start, then moves to the normal rendered state. Leaving starts from the current state, applies leave-active and leave-from, then transitions toward leave-to. Vue removes the element after the CSS transition or animation completes. In Vue's class naming, enter-from and leave-to are the endpoints that usually hold hidden styles; enter-to and leave-from represent the visible state and may be implicit.
The active class is present for the whole duration. Put duration and easing there, and put the start or end visual values in endpoint classes. Opacity and transform are often smooth because browsers can usually composite them without repeated layout calculation. Animating height can be appropriate for an accordion, but it causes layout work and needs a known or measured endpoint. Start with a short duration, often around 150 to 250 milliseconds for a small response, and tune with the actual interaction rather than making every element move at the same speed.
Use v-if when the element is added to or removed from the DOM. Use v-show when it should remain mounted and visibility changes frequently. A rarely opened dialog may be removed; a frequently toggled panel may be cheaper to keep mounted. Both can participate in a transition. Do not put unrelated conditional children directly inside Transition unless you use a keyed replacement pattern: Vue expects one transitioning child at a time. A stable element root makes the class sequence predictable.
A transition should clarify a state change, not delay access. A disappearing toast should not keep an invisible button keyboard-focusable during its leave phase. A modal's closing animation should not leave contents available to assistive technology after the user considers it closed. For important content, state changes must remain understandable when motion is reduced or unavailable. The visual effect is optional; the semantic state change is not.
This is frequently tested in Vue interviews through a concrete question: how does Vue know when it can remove a leaving node? It observes CSS transition or animation completion, or receives an explicit completion signal from JavaScript hooks. Explain the class sequence and one lifecycle choice to show the mechanism rather than memorizing a component name.
The transition wrapper itself does not add a DOM element, which is useful when the surrounding layout depends on a particular parent-child structure. The child must still have a single root element for the normal CSS-class workflow. If a component is the child, Vue can pass transition classes to its root; a fragment with several roots makes the target ambiguous. When the component controls its own roots, expose or forward the expected class deliberately. Verify the rendered DOM instead of assuming a component boundary creates a wrapper.
CSS selectors must match the actual class prefix. With scoped styles, Vue rewrites selectors, but the transition classes are still placed on the transitioning node. A selector targeting only a nested descendant will not affect the root. Inspect the element during the first frames of entry and exit, and confirm that the computed transition property is nonzero. A valid state toggle can appear instantaneous when another selector overrides opacity or transition-duration.
Vue detects completion from CSS events. If multiple properties use different durations, the longest relevant transition controls removal. A nested element with a longer animation may finish after the root; specify an explicit duration on Transition when the nested effect should determine completion. Do not guess with a separate timeout unless application logic truly needs it. A component after-enter or after-leave event is more reliable when code must react to completed motion.
Give a saved form a transition without hiding its state
Build a dismissible saved message
Suppose a form displays a success message when its request resolves. The message should enter after a successful response and leave when the user dismisses it or a timer expires. Keep the text present only while it is relevant, and make sure the animation does not turn a persistent state into a timing-dependent one. Use a named Transition around a paragraph controlled by v-if. The paragraph can use role=status so assistive technology announces the update without moving focus.
If the message contains an action such as Undo, decide whether the timer pauses while it is focused or hovered. Silently removing a focused control creates a poor interaction. A standalone informational status usually should not receive focus. If the operation fails, render a separate error message and do not reuse the success animation to imply completion. The state in the component remains the source of truth; CSS only visualizes it.
Test the behavior at the state boundary. Trigger the success branch and inspect that the enter-from class is temporary, the active class remains for the configured duration, and the element reaches its normal opacity. Then hide it and verify the leave classes appear before the node is removed. Clicking twice quickly should reset the timer rather than create competing timeouts. If the timer fires while a leave is already running, the state should remain coherent. Clear timers when the component unmounts so a delayed callback does not update dead component state.
When the animation does not run, inspect rendered classes first. A misspelled Transition name is common: name saved requires saved-enter-active, not v-enter-active. Next inspect whether the conditional branch actually changes, whether the element has one stable root, and whether scoped styles compile to selectors that match the generated element. Developer tools show the computed transition property and final class sequence. A zero duration, overridden opacity, or selector aimed at the wrong node can make valid Vue hooks look broken.
Use reduced-motion emulation to verify the media query. Users who request reduced motion should not wait through a long slide to understand that the message appeared. The content and announcement still happen; only visual movement is shortened. Avoid a second delayed JavaScript timer for animation completion when CSS already controls the transition. If application logic truly must wait for completion, use the component's after-enter or after-leave event instead of guessing the duration in another timer.
For a modal, also verify focus behavior. Opening may move focus into the dialog, and closing should return it to the control that opened the dialog. The leave animation means the modal node can remain in the DOM for a short interval after the application begins closing it. Disable its interactive content or manage the focus trap during that interval so a user cannot tab into an interface that is logically closed. If the modal is teleported elsewhere in the DOM, inspect where the transition classes are applied and ensure the overlay and panel do not finish at conflicting times.
A practical debugging sequence is to reproduce one transition, inspect its class list frame by frame, inspect computed styles, and then compare the CSS selector with the name prop. Check whether a parent rule sets display:none immediately, because display cannot interpolate like opacity. Check whether reduced-motion rules intentionally shorten the animation. Finally, test rapid toggles and unmounting. This sequence distinguishes a state bug from a selector bug and from expected accessibility behavior.
For an interview exercise, narrate the state change, CSS class phases, and DOM removal timing. Then explain what would change for a persistent panel using v-show or a dialog that also requires focus management. That connects the component to a real interaction rather than merely listing class names.
When should a transition delay removal, and when should it not?
Motion has a cost and a job
Transition is useful when motion communicates a state change: a toast appeared, a disclosure opened, or a dialog is closing. It can make a quick change easier to track and give feedback that an action succeeded. It becomes harmful when it delays an urgent action, repeats on every small update, or animates enough content to make the page feel slow. Keep animation short and tied to one state change. Avoid animating content that updates continuously, because the user may not be able to follow it.
The component handles one child element's enter and leave lifecycle. For a list whose items insert, leave, and move independently, use TransitionGroup. For a continuous effect such as a pulsing loader, CSS keyframes are usually a better fit. For a route page, a transition belongs around the route component and needs a stable key if two route instances must be treated as distinct. If no visual motion improves comprehension, render the state directly and skip the component.
A transition affects layout timing. During leave, the node remains present until the effect completes. If it participates in normal flow, following content may not move until the node is removed. For a collapsing region, animate height deliberately or use a leave strategy that lets layout respond as expected. An absolutely positioned toast avoids shifting surrounding content, but requires a container and responsive placement. State the layout consequence before choosing a CSS property; animation behavior is not only color and opacity.
CSS and JavaScript completion need one owner. Vue can infer the end from CSS transition or animation events, but multiple properties with different durations can make the longest property determine completion. If a nested child has a longer animation than the root, use an explicit duration that matches the nested effect. JavaScript hooks support animation libraries and imperative orchestration; when using them, call the provided completion callback or mark the hook as explicitly controlled so Vue does not wait for a CSS event that will never happen. Do not combine inferred and explicit timing accidentally.
Reduced motion should be part of the design. A media query can remove translation or shorten duration, but the animation must not carry the only cue that a control changed. Keep visible labels, status announcements, and focus behavior correct without motion. For repeated or large movement, consider whether the effect causes discomfort and whether the user can complete the task with reduced motion enabled.
In an interview, compare Transition with direct rendering, v-show, TransitionGroup, and keyframe animation. Explain the decision through the change being represented, whether the element is removed or retained, and who owns timing. Mention that a leaving node stays mounted through the effect and that errors often come from a class mismatch or CSS duration. Then describe how you would verify keyboard behavior and reduced motion. Concrete trade-offs make the answer useful beyond reciting class names.
A practical rule is to animate only the element whose state changed, keep duration short, and test interaction while it is entering and leaving. If a user can activate a control during its exit, define what that action means. If repeated toggles interrupt the transition, test rapid toggling in the browser and decide whether reversal is acceptable. The state should remain the source of truth; CSS should visualize it rather than maintain a competing state machine.
There are cases where Vue cannot infer the right completion boundary from the root. A nested animation may outlast the parent, a CSS animation may have infinite iteration, or a JavaScript animation library may own the timing. Infinite effects cannot be treated as a normal leave completion because the element would never be removed. Use an explicit finite duration or a JavaScript hook that signals completion. For large enter/leave effects, set the event type or duration intentionally and document why, so future CSS changes do not leave stale timing assumptions.
Do not use transitions as a substitute for state design. A loading indicator should reflect a real pending operation and disappear when that operation settles; a decorative timer that keeps it visible can mislead users. A confirmation dialog should not become inaccessible merely because its opacity is zero. Keep business state, semantic visibility, and animation progress conceptually separate. The framework coordinates the DOM lifecycle, but the application decides whether the interaction is safe and meaningful.
A useful review asks three questions: what user-visible state changed, what visual feedback improves comprehension, and what must remain true during the animation? If those answers are vague, remove the effect or simplify it. If they are clear, choose a property and duration that reinforce the state without blocking the next action. This decision process is more robust than adopting a transition on every conditional element by default.
Quiz
1. When does Vue normally remove a child that is leaving through CSS?
2. Which classes usually contain the duration and easing for both entry and exit?
3. What should you inspect first when a named transition has no visible effect?
4. Which case is a better fit for TransitionGroup than Transition?
Flashcards
Question
What does Transition coordinate?
Click to reveal answer
Answer
The enter and leave DOM lifecycle of one child element while CSS or JavaScript provides the effect.
Question
What changes when a Transition has a name prop?
Click to reveal answer
Answer
Vue uses that name as the prefix for generated enter and leave classes.
Question
When would v-show be preferable to v-if?
Click to reveal answer
Answer
When frequent toggles make retaining the mounted element preferable to destroying and recreating it.
Question
Why does a leaving node remain mounted briefly?
Click to reveal answer
Answer
Vue waits for the transition or animation to complete before removing it.
Question
What should a reduced-motion design preserve?
Click to reveal answer
Answer
The semantic state change and accessible communication, even when visual movement is shortened or removed.
Revision Notes
Key Takeaways
- 1. Transition coordinates one child element?s enter and leave lifecycle; CSS supplies the visual effect.
- 2. A named Transition changes the expected class prefix, so class names must match the name prop.
- 3. Use v-if for mount and removal, and v-show when the element should remain mounted but change visibility.
- 4. During leave, the DOM node stays present until the CSS effect or explicit hook completes.
- 5. Keep motion brief, preserve semantic state, and support reduced-motion preferences.
Interview Tips
- • Describe the enter and leave class sequence and explain when Vue removes a leaving node.
- • Compare v-if and v-show based on lifecycle and toggle frequency.
- • Name a diagnostic step for a transition that appears not to run, such as checking generated classes or computed CSS.
- • Mention reduced motion and the layout consequences of animating height or position.
Cheat Sheet
The Transition Component Cheat Sheet
Phase: Transitions and Animations | Level: beginner
Key points:
- Transition applies enter and leave class hooks around a single element's toggling.
- The enter-from and leave-to classes define the start and end visual states.
- Duration props accept one value for both phases or separate enter and leave numbers.
- Transition only affects one child element and must not be toggled off its element root.
Tags: vue, transition, animation
Continue Learning
Before You Start
- No prerequisites listed.