Vue <Transition> and <TransitionGroup> are built-in components that animate elements when they enter or leave the DOM. Vue applies CSS classes at each step of the animation automatically when v-if, v-show, or dynamic components toggle.
Instead of manually adding and removing CSS timer classes in JavaScript, you define simple CSS rules for enter and leave states. Vue detects the animation duration from CSS and removes elements only after the exit animation finishes.
flowchart LR
EnterFrom["fade-enter-from"] --> EnterActive["fade-enter-active"] --> EnterTo["fade-enter-to"]
LeaveFrom["fade-leave-from"] --> LeaveActive["fade-leave-active"] --> LeaveTo["fade-leave-to"]
When using <Transition name="fade">, Vue toggles six predictable CSS classes:
fade-enter-from and fade-enter-to: Starting and ending styles for elements entering the DOM.fade-enter-active: Active class during the entire enter phase, where you set transition properties.fade-leave-from and fade-leave-to: Starting and ending styles for elements leaving the DOM.fade-leave-active: Active class during the exit animation.Use <Transition> for a single conditional element and <TransitionGroup> when animating items inside a v-for list.
<script setup>
import { ref } from 'vue';
const showBanner = ref(true);
const items = ref(['Alpha', 'Beta', 'Gamma']);
function addItem() {
items.value.push(`Item ${items.value.length + 1}`);
}
function removeItem(index) {
items.value.splice(index, 1);
}
</script>
<template>
<div class="animation-demo">
<button @click="showBanner = !showBanner">Toggle Banner</button>
<Transition name="fade" mode="out-in">
<div v-if="showBanner" key="banner" class="banner">
Notification Alert Banner
</div>
</Transition>
<button @click="addItem">Add List Item</button>
<TransitionGroup name="list" tag="ul">
<li v-for="(item, index) in items" :key="item">
<span>{{ item }}</span>
<button @click="removeItem(index)">x</button>
</li>
</TransitionGroup>
</div>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(24px);
}
</style>
:key Inside <TransitionGroup>: Every direct child inside <TransitionGroup> must have a unique :key. Without keys, Vue cannot track which list items moved or exited.<Transition>: <Transition> animates one element or component at a time. When switching between two elements, ensure only one branch renders at a time or use mode="out-in".tag on <TransitionGroup>: Unlike <Transition>, <TransitionGroup> can render a wrapper tag such as tag="ul" so your HTML stays semantic.mode="out-in" do on <Transition>?With mode="out-in", Vue waits for the outgoing element to finish its leave animation before starting the incoming element's enter animation. This prevents two elements from jumping past each other.
<Transition> animate on initial page render?Yes. Add the appear attribute (<Transition name="fade" appear>) to run the enter animation when the component first mounts.
<Transition> emits JavaScript hooks such as @enter, @before-enter, and @leave. Pass :css="false" when driving animations purely with JavaScript.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With