Transitions
`
Single, list, JS hooks, and route transitions
EXAMPLE
<!-- 1) Single-element fade -->
<script setup>
import { ref } from 'vue';
const open = ref(false);
</script>
<template>
<button @click='open = !open'>Toggle</button>
<Transition name='fade'>
<p v-if='open'>Hello</p>
</Transition>
</template>
<style>
.fade-enter-active, .fade-leave-active { transition: opacity .15s ease; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>
<!-- 2) Slide + fade together -->
<style>
.slide-enter-active { transition: transform .25s cubic-bezier(.2,.7,.2,1), opacity .2s; }
.slide-leave-active { transition: transform .15s ease-in, opacity .15s; }
.slide-enter-from { opacity: 0; transform: translateY(8px); }
.slide-leave-to { opacity: 0; transform: translateY(-8px); }
</style>
<!-- 3) Transition between two elements (use a key on each) -->
<Transition name='slide' mode='out-in'>
<p :key='step'>{{ step === 1 ? 'Step 1' : 'Step 2' }}</p>
</Transition>
<!-- 4) TransitionGroup — animate ADDED / REMOVED / MOVED list items -->
<script setup>
import { ref } from 'vue';
const items = ref([1, 2, 3]);
function shuffle() {
items.value = items.value.slice().sort(() => Math.random() - 0.5);
}
function add() { items.value.push(items.value.length + 1); }
</script>
<template>
<button @click='shuffle'>Shuffle</button>
<button @click='add'>Add</button>
<TransitionGroup name='list' tag='ul'>
<li v-for='n in items' :key='n'>{{ n }}</li>
</TransitionGroup>
</template>
<style>
.list-move,
.list-enter-active,
.list-leave-active { transition: all .35s cubic-bezier(.2,.7,.2,1); }
.list-enter-from,
.list-leave-to { opacity: 0; transform: translateY(6px); }
.list-leave-active { position: absolute; } /* prevents layout jump on remove */
</style>
<!-- 5) JS hooks — run code at lifecycle points (mix with GSAP / anime.js) -->
<Transition
@before-enter='(el) => { el.style.opacity = 0; }'
@enter='(el, done) => { el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 }).onfinish = done; }'
@leave='(el, done) => { el.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 150 }).onfinish = done; }'
>
<div v-if='show'>Custom-animated</div>
</Transition>
<!-- 6) Route-level transitions (Vue Router 4) -->
<router-view v-slot='{ Component }'>
<Transition name='fade' mode='out-in'>
<component :is='Component' />
</Transition>
</router-view>
<!-- 7) Respect prefers-reduced-motion -->
<style>
@media (prefers-reduced-motion: reduce) {
.fade-enter-active, .fade-leave-active,
.slide-enter-active, .slide-leave-active,
.list-move, .list-enter-active, .list-leave-active {
transition: none !important;
}
}
</style>
<!-- 8) mode='out-in' vs 'in-out'
'out-in' (default): old leaves, then new enters. Good for content swaps.
'in-out': new enters on top of old. Good for fade through hero images.
-->
Why it matters
`
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…