We use cookies to enhance your experience on the site
CodeWorlds

TransitionGroup - Animating Lists

The NOVA LAB station module list is constantly changing — we add new life support systems, remove damaged sensors, sort alerts by priority. Each time, we want the list changes to be visually smooth.

<TransitionGroup>
is a Vue component designed specifically for animating elements rendered with
v-for
.

Basic Usage

1<TransitionGroup name="list" tag="ul">
2  <li v-for="item in items" :key="item.id">
3    {{ item.name }}
4  </li>
5</TransitionGroup>

Each element added to the list animates on entry, and removed ones animate on exit. This automatic behavior is based on the same CSS classes as

<Transition>
.

Key Differences from
<Transition>

<TransitionGroup>
differs from
<Transition>
in several important ways:

  1. It renders a DOM element — unlike

    <Transition>
    ,
    <TransitionGroup>
    renders an HTML element by default. You control it with the
    tag
    attribute:
    tag="ul"
    ,
    tag="div"
    ,
    tag="section"
    . If you don't want an extra element, you can set
    tag="template"
    (Vue 3.5+).

  2. Each element must have a unique

    :key
    — Vue needs to track the identity of individual elements to know which ones to add, remove, and move. Never use the array index as a key!

  3. It supports multiple elements simultaneously — it's not limited to a single element like

    <Transition>
    . Multiple elements can enter and leave at the same time.

  4. Additional

    -move
    class — animates the movement of elements when the list order changes. This is a unique feature of
    <TransitionGroup>
    .

  5. The

    mode
    attribute is not supported — because we're not switching between one element and another.

CSS Classes for Lists

TransitionGroup uses the same classes as Transition plus an additional

-move
class:

1/* New element entering */
2.list-enter-active {
3  transition: all 0.5s ease;
4}
5.list-enter-from {
6  opacity: 0;
7  transform: translateX(30px);
8}
9
10/* Element being removed */
11.list-leave-active {
12  transition: all 0.5s ease;
13  position: absolute; /* IMPORTANT! */
14}
15.list-leave-to {
16  opacity: 0;
17  transform: translateX(-30px);
18}
19
20/* Remaining elements moving */
21.list-move {
22  transition: transform 0.5s ease;
23}

Move Transitions — The Key Mechanic

This is the most interesting feature of

<TransitionGroup>
. When you add or remove an element from a list, the remaining elements need to shift to new positions. Vue automatically adds the
-move
class to elements that change position, and animates their movement using CSS transforms.

For move transitions to work correctly, leaving elements must have

position: absolute
in the
-leave-active
class. This takes the leaving element "out of flow" so the rest can smoothly shift:

1.list-leave-active {
2  position: absolute;
3  /* Optionally: preserve width */
4  width: 100%;
5}
6
7.list-move {
8  transition: transform 0.5s ease;
9}

Practical Example — Station Alert List

1<template>
2  <div class="alert-panel">
3    <button @click="addAlert">Add alert</button>
4
5    <TransitionGroup name="alert" tag="div" class="alert-list">
6      <div
7        v-for="alert in alerts"
8        :key="alert.id"
9        class="alert-item"
10        :class="alert.level"
11      >
12        {{ alert.message }}
13        <button @click="removeAlert(alert.id)">x</button>
14      </div>
15    </TransitionGroup>
16  </div>
17</template>
18
19<script setup>
20import { ref } from 'vue'
21
22const alerts = ref([])
23let nextId = 1
24
25function addAlert() {
26  alerts.value.unshift({
27    id: nextId++,
28    message: `Alert #${nextId - 1}: Oxygen level check`,
29    level: Math.random() > 0.5 ? 'warning' : 'critical'
30  })
31}
32
33function removeAlert(id) {
34  alerts.value = alerts.value.filter(a => a.id !== id)
35}
36</script>
1.alert-enter-active, .alert-leave-active {
2  transition: all 0.4s ease;
3}
4.alert-enter-from {
5  opacity: 0;
6  transform: translateX(-30px);
7}
8.alert-leave-to {
9  opacity: 0;
10  transform: translateX(30px);
11}
12.alert-leave-active {
13  position: absolute;
14}
15.alert-move {
16  transition: transform 0.4s ease;
17}

The effect: new alerts enter from the left, removed ones exit to the right, and the rest smoothly shift into place. Exactly like on a space station alert panel!

Go to CodeWorlds