Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/transition-nested-duration.md
1---2title: Specify Explicit Duration for Nested Transitions3impact: MEDIUM4impactDescription: Nested transitions with different timings may end prematurely when Vue detects only the root element's transition end5type: gotcha6tags: [vue3, transition, animation, duration, nested, timing]7---89# Specify Explicit Duration for Nested Transitions1011**Impact: MEDIUM** - When transitioning elements that contain nested child elements with different animation timings, Vue by default listens only for the first `transitionend` or `animationend` event on the **root** transition element. This means if inner elements have longer or delayed animations, they may be cut off when the root element's transition completes.1213## Task Checklist1415- [ ] Identify if your transition contains nested elements with different animation durations16- [ ] Use the `:duration` prop to specify the total time Vue should wait17- [ ] Consider using separate enter and leave durations if they differ18- [ ] Test animations to ensure nested elements complete fully1920**Problematic Code:**21```vue22<template>23<!-- BAD: Inner element has longer animation that gets cut off -->24<Transition name="nested">25<div v-if="show" class="outer">26<div class="inner">Hello</div>27</div>28</Transition>29</template>3031<style>32.nested-enter-active .outer,33.nested-leave-active .outer {34transition: opacity 0.3s ease;35}3637.nested-enter-active .inner,38.nested-leave-active .inner {39/* This 0.5s animation gets cut off at 0.3s when outer finishes! */40transition: transform 0.5s ease 0.2s; /* 0.2s delay + 0.5s = 0.7s total */41}4243.nested-enter-from .outer,44.nested-leave-to .outer {45opacity: 0;46}4748.nested-enter-from .inner,49.nested-leave-to .inner {50transform: translateX(-30px);51}52</style>53```5455**Correct Code:**56```vue57<template>58<!-- GOOD: Explicit duration ensures all nested animations complete -->59<Transition name="nested" :duration="700">60<div v-if="show" class="outer">61<div class="inner">Hello</div>62</div>63</Transition>64</template>6566<style>67.nested-enter-active .outer,68.nested-leave-active .outer {69transition: opacity 0.3s ease;70}7172.nested-enter-active .inner,73.nested-leave-active .inner {74/* Now this animation completes fully */75transition: transform 0.5s ease 0.2s;76}7778.nested-enter-from .outer,79.nested-leave-to .outer {80opacity: 0;81}8283.nested-enter-from .inner,84.nested-leave-to .inner {85transform: translateX(-30px);86}87</style>88```8990## Different Enter and Leave Durations9192```vue93<template>94<!-- GOOD: Separate durations for enter and leave -->95<Transition96name="complex"97:duration="{ enter: 500, leave: 800 }"98>99<div v-if="show" class="container">100<h1 class="title">Title</h1>101<p class="content">Content with staggered animation</p>102</div>103</Transition>104</template>105106<style>107/* Enter: title first, then content */108.complex-enter-active .title {109transition: opacity 0.3s ease, transform 0.3s ease;110}111112.complex-enter-active .content {113transition: opacity 0.3s ease 0.2s, transform 0.3s ease 0.2s;114}115116/* Leave: content first, then title (reverse order) */117.complex-leave-active .content {118transition: opacity 0.3s ease, transform 0.3s ease;119}120121.complex-leave-active .title {122transition: opacity 0.5s ease 0.3s, transform 0.5s ease 0.3s;123}124125.complex-enter-from .title,126.complex-enter-from .content,127.complex-leave-to .title,128.complex-leave-to .content {129opacity: 0;130transform: translateY(20px);131}132</style>133```134135## Choreographed Staggered Animations136137```vue138<template>139<Transition name="stagger" :duration="800">140<div v-if="show" class="card">141<img class="card-image" src="..." />142<h2 class="card-title">Title</h2>143<p class="card-body">Body text...</p>144<button class="card-action">Action</button>145</div>146</Transition>147</template>148149<style>150/* Staggered entrance: image -> title -> body -> action */151.stagger-enter-active .card-image { transition: all 0.3s ease; }152.stagger-enter-active .card-title { transition: all 0.3s ease 0.1s; }153.stagger-enter-active .card-body { transition: all 0.3s ease 0.2s; }154.stagger-enter-active .card-action { transition: all 0.3s ease 0.3s; }155/* Total: 0.3s delay + 0.3s animation = 0.6s, but use 800ms for safety */156157.stagger-enter-from .card-image,158.stagger-enter-from .card-title,159.stagger-enter-from .card-body,160.stagger-enter-from .card-action {161opacity: 0;162transform: translateY(10px);163}164</style>165```166167## Calculating Duration168169Use this formula to calculate the correct duration:170```171duration = max(delay + animation_duration) for all nested elements172```173174Example:175- Element A: no delay, 300ms duration = 300ms total176- Element B: 100ms delay, 300ms duration = 400ms total177- Element C: 200ms delay, 500ms duration = 700ms total178179**Required `:duration`**: 700 (or slightly higher for safety margin)180181## Reference182- [Vue.js Transition - Nested Transitions](https://vuejs.org/guide/built-ins/transition.html#nested-transitions-and-explicit-transition-durations)183