100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
JavaScript

Transitions and Animations

Learn how Vue's built-in Transition and TransitionGroup components animate elements entering, leaving, and reordering using CSS classes and hooks.

Working with Data & APIsIntermediate9 min readJul 9, 2026
Analogies

Transitions and Animations

Vue ships built-in <Transition> and <TransitionGroup> components that automate the tedious part of animating elements as they enter or leave the DOM — Vue detects when a wrapped element is about to be inserted or removed (because of v-if, v-show, dynamic components, or route changes) and, instead of applying the change instantly, gives you a window of time to run a CSS transition, a CSS animation, or JavaScript hooks before completing the DOM operation. This means you write ordinary CSS classes and let Vue handle exactly when to add and remove them relative to the actual DOM mutation.

🏏

Cricket analogy: Like a stadium's automated roof system that detects rain starting (an element about to enter) and gives itself a timed window to smoothly close the panels with a motorized transition rather than slamming shut instantly, using the same simple hydraulic controls for every match.

The Six Transition CSS Classes

For a <Transition name="fade">, Vue applies up to six class combinations at the right moments: fade-enter-from/fade-enter-active/fade-enter-to for the entering phase, and fade-leave-from/fade-leave-active/fade-leave-to for the leaving phase. The -active classes are present for the whole duration and are where you typically declare the transition CSS property itself; the -from/-to classes describe the starting and ending style states that the browser interpolates between.

🏏

Cricket analogy: Like a floodlight dimming sequence with a defined 'ramping' phase (-active, where the dimmer's fade rate is set) bracketed by a starting brightness state (-from) and an ending brightness state (-to), so the lights smoothly ramp from full glare down to off rather than switching abruptly.

vue
<script setup>
import { ref } from 'vue'

const showPanel = ref(false)
</script>

<template>
  <button @click="showPanel = !showPanel">Toggle</button>

  <Transition name="fade-slide">
    <div v-if="showPanel" class="panel">Panel content</div>
  </Transition>
</template>

<style scoped>
.fade-slide-enter-active,
.fade-slide-leave-active {
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.fade-slide-enter-from,
.fade-slide-leave-to {
  opacity: 0;
  transform: translateY(-8px);
}
</style>

Animating Lists With TransitionGroup

<Transition> only wraps a single element (or one element at a time when toggling between two), so animating a v-for list — items being added, removed, or reordered — requires <TransitionGroup> instead. Unlike <Transition>, <TransitionGroup> renders a real wrapper element by default (a <span> unless you set tag) and additionally applies a -move class using FLIP-technique CSS transforms so that when items shift position (e.g. after a sort or a removal shrinking the list), the remaining items animate smoothly to their new positions rather than jumping instantly.

🏏

Cricket analogy: Like a single player walking out to bat can get an individual entrance ceremony, but when the whole fielding team repositions after a bowling change, you need a coordinated team-wide reshuffle (TransitionGroup) with an actual huddle formation on the ground (wrapper element), where each fielder smoothly jogs to their new position (FLIP -move) rather than teleporting there.

React's Transition Group libraries (like react-transition-group or Framer Motion) require more manual wiring of enter/exit states; Vue's approach is closer to Angular's built-in animation triggers in that the framework itself detects DOM insertion/removal timing and exposes named CSS-class hooks automatically.

JavaScript Hooks for Complex Animations

For animations that CSS classes alone can't express — staggering multiple elements, integrating a JS animation library like GSAP, or coordinating with measurements of the DOM — <Transition> exposes JavaScript hooks (@before-enter, @enter, @after-enter, @leave, and their @after-leave counterparts) as component events. When using JS-only hooks without any CSS transition classes, you must call the done callback provided to @enter/@leave (or set :css="false") so Vue knows exactly when the animation has finished and it's safe to proceed.

🏏

Cricket analogy: Like a stadium's elaborate opening ceremony that needs a stage manager's manual 'go' cues for each fireworks burst (JS hooks) rather than a simple timed light dimmer, calling a 'sequence complete' signal (done callback) explicitly so the ground crew knows exactly when it's safe to start the toss.

A common pitfall is forgetting that <Transition> only animates a single root element being toggled — wrapping a v-for block directly in <Transition> (instead of <TransitionGroup>) will not animate individual list items correctly and often produces confusing behavior since Vue can't tell which specific item is entering or leaving.

  • <Transition> automatically applies enter/leave CSS classes around elements toggled by v-if, v-show, or dynamic components.
  • The six classes (enter-from/active/to, leave-from/active/to) let you declare transition timing in the -active class and start/end states in -from/-to.
  • <TransitionGroup> animates v-for lists, including a -move class for smoothly repositioning items using FLIP-style transforms.
  • JavaScript hooks (@enter, @leave, etc.) enable complex or library-driven animations, requiring an explicit done() call when :css="false".
  • TransitionGroup renders a real wrapper element (default span) unlike Transition, which does not add extra DOM nodes.
  • Using <Transition> around a v-for list instead of <TransitionGroup> will not animate individual items correctly.

Practice what you learned

Was this page helpful?

Topics covered

#JavaScript#VueJsStudyNotes#WebDevelopment#TransitionsAndAnimations#Transitions#Animations#Six#Transition#StudyNotes#SkillVeris