Hoofdstuk 11 van 11

Vue 3-tutorial: animeren met Transition en TransitionGroup

geverifieerd op 2 september 2026 · 5 min

Kort antwoord

<Transition> animeert één element bij het verschijnen en verdwijnen, <TransitionGroup> animeert een lijst. Vue past CSS-klassen toe, jouw stijlblad bepaalt het effect. Let op: in Vue 3 heten de beginklassen -enter-from en -leave-from, niet -enter en -leave zoals in Vue 2.

Aan het einde van dit hoofdstuk, kun je het verschijnen, verdwijnen en verschuiven van elementen animeren, zonder bibliotheek.

Een element dat plots verschijnt, geeft een schokkerig effect. Vue levert twee ingebouwde componenten, <Transition> en <TransitionGroup>, die op het juiste moment CSS-klassen toepassen om het verschijnen en verdwijnen te animeren. Geen enkele bibliotheek te installeren.

Het principe

Wikkel een element waarvan de weergave van een voorwaarde afhangt in <Transition>. Vue animeert het niet zelf: het voegt klassen toe en haalt ze weg, en jouw CSS bepaalt het effect.

Zes klassen dekken de volledige cyclus.

css
/* binnenkomst */
.v-enter-from     /* begintoestand, vlak voor het invoegen toegepast */
.v-enter-active   /* gedurende de hele binnenkomst: hier hoort transition */
.v-enter-to       /* eindtoestand */

/* vertrek */
.v-leave-from     /* begintoestand van het vertrek */
.v-leave-active   /* gedurende het hele vertrek */
.v-leave-to       /* eindtoestand, vlak voor het verwijderen uit de DOM */

Het voorvoegsel v- hoort bij een transitie zonder naam. Met name="fade" worden de klassen fade-enter-from, fade-enter-active, enzovoort.

De valkuil van code van het web

In Vue 2 heetten de beginklassen .fade-enter en .fade-leave, zonder achtervoegsel. Vue 3 heeft ze hernoemd naar -enter-from en -leave-from. Een voorbeeld dat uit een oud artikel is gekopieerd, levert dus helemaal geen animatie bij het verschijnen op, zonder ook maar één foutmelding. Doet je transitie niets, controleer dan eerst dit punt.

De beschikbaarheid animeren

In ProductDisplay.vue wisselt de voorraadmelding tussen twee alinea’s, afhankelijk van de variant waar de muis boven staat. Wikkel ze in:

src/components/ProductDisplay.vue
<Transition name="fade" mode="out-in">
  <p v-if="inStock" key="in">En stock</p>
  <p v-else key="out">En rupture</p>
</Transition>

Beschrijf daarna het effect in het stijlblad, zoals in het hoofdstuk over klassen en stijlen:

src/assets/boutique.css
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: translateY(-10px);
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity .3s ease, transform .3s ease;
}

Ga met de muis over de kleurbolletjes: de melding vervaagt in plaats van te springen.

mode="out-in" wacht tot het oude element weg is voordat het nieuwe wordt ingevoegd. Zonder deze modus bestaan beide alinea’s een fractie van een seconde naast elkaar en overlappen ze.

Wat Transition aanvaardt

Eén element tegelijk. Dat is de belangrijkste beperking: <Transition> animeert één enkel kind, geen lijst.

Hij treedt in drie situaties in werking: bij een v-if, bij een v-show, of bij een componentwissel via <component :is>. Wil je een transitie afdwingen tussen twee elementen van hetzelfde type, geef ze dan verschillende key-waarden, zoals hierboven.

Een lijst animeren

Voor een lijst heb je <TransitionGroup> nodig. Twee verschillen: hij aanvaardt meerdere kinderen en rendert zelf een containerelement als je daarom vraagt met tag.

Vervang in ReviewList.vue de <ul>:

src/components/ReviewList.vue
<template>
  <div class="review-container">
    <h3>Avis</h3>
    <TransitionGroup name="liste" tag="ul">
      <li v-for="review in reviews" :key="review.id">
        {{ review.name }} a mis {{ review.rating }} étoiles
        <br>
        « {{ review.review }} »
      </li>
    </TransitionGroup>
  </div>
</template>

Elk kind heeft een unieke en stabiele key nodig. De index volstaat hier niet: die verandert bij elke invoeging, en Vue zou niet meer weten welk element nieuw is. Laten we elke review een identificatie geven op het moment van toevoegen:

src/components/ProductDisplay.vue
<script setup>
function addReview(review) {
  reviews.value.push({ ...review, id: crypto.randomUUID() })
}
</script>

crypto.randomUUID() is beschikbaar in alle actuele browsers, op pagina’s die via HTTPS of vanaf localhost worden geserveerd.

De CSS krijgt er één klasse bij, -move, die de verplaatsing van de overige elementen animeert wanneer een buur verdwijnt:

src/assets/boutique.css
.liste-enter-from,
.liste-leave-to {
  opacity: 0;
  transform: translateX(24px);
}

.liste-enter-active,
.liste-leave-active,
.liste-move {
  transition: all .3s ease;
}

Plaats meerdere reviews: elke review schuift binnen, en de andere schikken zich soepel opnieuw.

Verdwijnen en verschuiven

Opdat -move bij verwijdering werkt, moet het vertrekkende element uit de flow worden gehaald, anders bewegen de andere pas op het einde van zijn animatie. Voeg position: absolute toe aan de klasse -leave-active wanneer je elementen verwijderbaar zijn.

Animeren bij de eerste weergave

Standaard wordt er bij de eerste render niets geanimeerd. Het attribuut appear verandert dat:

html
<Transition name="fade" appear>
  <p>Visible dès le chargement, en fondu</p>
</Transition>

CSS-animaties en hooks

transition is niet de enige optie: een CSS-animation werkt ook, toegepast op de klasse -enter-active.

Om een JavaScript-animatiebibliotheek aan te sturen, zendt <Transition> bij elke stap gebeurtenissen uit:

html
<Transition
  :css="false"
  @before-enter="avantEntree"
  @enter="entree"
  @after-enter="apresEntree"
  @leave="sortie"
>
  <p v-if="visible">Contenu</p>
</Transition>

Met :css="false" beheert Vue de klassen niet langer en geeft het jou de controle. De functies enter en leave krijgen dan het element en een callback done die je aanroept zodra de animatie klaar is:

javascript
function entree(el, done) {
  // animatie met de bibliotheek van je keuze
  done()
}

Beweging is niet altijd gewenst

Sommige mensen schakelen animaties uit op systeemniveau, onder meer om misselijkheid door beweging te vermijden. Respecteer die instelling:

src/assets/boutique.css
@media (prefers-reduced-motion: reduce) {
  .fade-enter-active,
  .fade-leave-active,
  .liste-enter-active,
  .liste-leave-active,
  .liste-move {
    transition: none;
  }
}

De interface blijft bruikbaar, alleen de animatie verdwijnt.

Dit is het einde van de tutorial

Je applicatie toont een product en zijn varianten, beheert een winkelmandje, valideert een formulier en animeert zijn toestandswissels. Je hebt reactiviteit, directives, componenten, props, gebeurtenissen en transities behandeld: genoeg om dagelijks Vue te lezen en te schrijven.

Voor het vervolg zijn er twee richtingen. Het delen van state tussen ver uit elkaar liggende componenten met Pinia, wanneer gebeurtenissen naar boven doorgeven lastig wordt. En routering met Vue Router, zodra de applicatie meerdere pagina’s heeft.

In de Options API

<Transition> en <TransitionGroup> zijn ingebouwde componenten: ze worden precies hetzelfde geschreven. Alleen de functies van de JavaScript-hooks verhuizen, naar de optie methods.

OefeningVoeg een transitie toe aan de productafbeelding zodat ze vervaagt bij het wisselen van variant. Je hebt daarvoor een key nodig die aan de gekozen variant hangt.

Veelgemaakte fouten

De klassen van Vue 2 gebruiken .fade-enter en .fade-leave zijn hernoemd naar -enter-from en -leave-from. Er wordt niets geanimeerd en er verschijnt geen enkele fout.
mode="out-in" vergeten Zonder deze modus bestaan het binnenkomende en het vertrekkende element een fractie van een seconde naast elkaar en overlappen ze.
De index als sleutel gebruiken in een TransitionGroup Vue kan het nieuwe element niet meer van de andere onderscheiden en animeert het verkeerde item.
Een geanimeerd component testen met Vue Test Utils Transities worden standaard door stubs vervangen. Geef global: { stubs: { 'transition-group': false } } mee om de echte weergave te zien.
Nieuwsbrief

Nieuwe tests, tutorials en projecten, per e-mail.

Reproduceerbare tests, geversioneerde code, gedateerde resultaten. Nooit spam.