• Fri, Mar 2026

Vue.js Transitions and Animations Explained Step-by-Step

Vue.js Transitions and Animations Explained Step-by-Step

This in-depth tutorial will guide you through the magical world of Vue.js transitions and animations. We’ll explore everything from simple CSS transitions to complex JavaScript animation hooks, transition groups, and a full practical example. By the end, you’ll know how to bring life to your Vue applications with smooth, delightful motion.

Introduction to Vue.js Transitions

Animations make the difference between an app that feels stiff and one that feels alive. Vue.js makes adding animations and transitions painless with its built-in <transition> and <transition-group> components.

Whenever an element enters or leaves the DOM, Vue lets you apply CSS or JavaScript animations without heavy boilerplate. Whether it’s fading in a modal, sliding a sidebar, or animating list reordering, Vue’s transition system is your new best friend.

Step 1: The Basics of the <transition> Component

The simplest way to animate in Vue is by wrapping an element with the <transition> component. Vue automatically detects when the element enters or leaves the DOM and applies CSS classes for you.

Example: Fading Text

<template>
  <div>
    <button @click="show = !show">Toggle</button>
    <transition name="fade">
      <p v-if="show">Hello Vue Animations!</p>
    </transition>
  </div>
</template>

<script setup>
import { ref } from "vue";
const show = ref(true);
</script>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>

Here’s what happens:

  • .fade-enter-from sets the starting style when the element enters.
  • .fade-enter-active defines the transition duration and easing.
  • .fade-leave-to applies when the element leaves.

Step 2: Transition Classes Explained

Vue adds and removes special classes during the transition lifecycle:

Default Transition Classes


<transition name="fade">
  <!-- Vue automatically applies these classes -->
</transition>
        

Classes applied:

  • fade-enter-from: Initial state before entering.
  • fade-enter-active: Transition properties while entering.
  • fade-enter-to: Final state after enter starts.
  • fade-leave-from: Initial state before leaving.
  • fade-leave-active: Transition properties while leaving.
  • fade-leave-to: Final state after leave starts.

Step 3: Using CSS Animations Instead of Transitions

Instead of transitions, you can use @keyframes animations. Vue will detect them the same way.

Example: Bouncing Text

<style>
.bounce-enter-active {
  animation: bounce-in 0.6s;
}
.bounce-leave-active {
  animation: bounce-out 0.6s forwards;
}
@keyframes bounce-in {
  0% { transform: scale(0.8); opacity: 0; }
  50% { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1); }
}
@keyframes bounce-out {
  0% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.8); opacity: 0; }
}
</style>

This creates a fun “bounce” effect on entry and a smooth shrink on exit.

Step 4: Transitioning Between Multiple Elements

Vue allows you to transition between two different elements or components by using the mode attribute.

<transition name="fade" mode="out-in">
  <component :is="view"></component>
</transition>

<script setup>
import { ref } from "vue";
const view = ref("login-form");
</script>

The mode="out-in" ensures the leaving element finishes before the new one enters.

Step 5: Using <transition-group> for Lists

The <transition-group> component animates lists when items are added, removed, or reordered.

Example: Animated To-Do List

<template>
  <div>
    <input v-model="newItem" placeholder="Add item" />
    <button @click="addItem">Add</button>
    <transition-group name="list" tag="ul">
      <li v-for="(item, index) in items" :key="item">
        {{ item }}
        <button @click="removeItem(index)">X</button>
      </li>
    </transition-group>
  </div>
</template>

<script setup>
import { ref } from "vue";
const items = ref(["Learn Vue", "Build UI"]);
const newItem = ref("");

const addItem = () => {
  if (newItem.value) {
    items.value.push(newItem.value);
    newItem.value = "";
  }
};

const removeItem = (index) => {
  items.value.splice(index, 1);
};
</script>

<style>
.list-enter-active, .list-leave-active {
  transition: all 0.5s ease;
}
.list-enter-from {
  opacity: 0;
  transform: translateY(20px);
}
.list-leave-to {
  opacity: 0;
  transform: translateY(-20px);
}
</style>

When items are added or removed, they smoothly fade and slide in or out.

Step 6: JavaScript Hooks for Advanced Animations

Sometimes CSS alone isn’t enough. Vue lets you hook into transition lifecycle methods to animate with JavaScript or external libraries like GSAP.

Example: Using JavaScript Hooks

<transition
  @before-enter="beforeEnter"
  @enter="enter"
  @leave="leave">
  <div v-if="show">Animate me!</div>
</transition>

<script setup>
import { ref } from "vue";
const show = ref(true);

const beforeEnter = (el) => {
  el.style.opacity = 0;
};
const enter = (el, done) => {
  setTimeout(() => {
    el.style.transition = "opacity 1s";
    el.style.opacity = 1;
    done();
  }, 100);
};
const leave = (el, done) => {
  el.style.transition = "opacity 1s";
  el.style.opacity = 0;
  setTimeout(done, 1000);
};
</script>

Here we control every part of the animation lifecycle with JavaScript.

Step 7: Full Practical Example — Animated Modal Component

Let’s put it all together by creating a reusable animated modal component with transitions.

<!-- Modal.vue -->
<template>
 <transition name="modal-fade">
  <div v-if="show">
   <div >
    <slot></slot>
    <button @click="$emit('close')">Close</button>
   </div>
  </div>
 </transition>
</template>

<script setup>
defineProps({
 show: Boolean
});
</script>

<style scoped>
.modal-fade-enter-active, .modal-fade-leave-active {
 transition: opacity 0.5s;
}
.modal-fade-enter-from, .modal-fade-leave-to {
 opacity: 0;
}
.modal-overlay {
 position: fixed;
 top: 0; left: 0; right: 0; bottom: 0;
 background: rgba(0,0,0,0.6);
 display: flex;
 align-items: center;
 justify-content: center;
}
.modal-content {
 background: white;
 padding: 20px;
 border-radius: 8px;
}
</style>

Using the Modal

<template>
  <div>
    <button @click="showModal = true">Open Modal</button>
    <Modal :show="showModal" @close="showModal = false">
      <h2>Hello Modal</h2>
      <p>This modal uses Vue transitions!</p>
    </Modal>
  </div>
</template>

<script setup>
import { ref } from "vue";
import Modal from "./Modal.vue";
const showModal = ref(false);
</script>

This modal fades in and out smoothly, making the UI feel professional and polished.

Best Practices for Vue.js Animations

  • Keep it subtle: Overly flashy animations can annoy users.
  • Use reusable components: Wrap animations into reusable UI components like modals or dropdowns.
  • Optimize performance: Use CSS transitions where possible; only fall back to JavaScript for complex cases.
  • Test on devices: Animations may feel different on desktop vs mobile.

Conclusion

Vue.js makes transitions and animations elegant and approachable. Whether you’re adding a subtle fade, animating list items, or building full-screen modals, Vue gives you the tools to make your interfaces feel alive. By practicing with <transition>, <transition-group>, and hooks, you’ll be able to craft smooth, delightful experiences that users love.

Now it’s your turn—go build something beautiful and animated in Vue!

This website uses cookies to enhance your browsing experience. By continuing to use this site, you consent to the use of cookies. Please review our Privacy Policy for more information on how we handle your data. Cookie Policy