KeepAlive include examples with different formats
The include prop of <KeepAlive> can be specified in three formats: comma-delimited string syntax '<KeepAlive include="a,b">', regex syntax with v-bind '<KeepAlive :include="/a|b/">', or array syntax with v-bind '<KeepAlive :include="[\'a\', \'b\']">'.
KeepAlive in-DOM template reference
When <KeepAlive> is used in in-DOM templates, it should be referenced as <keep-alive> (lowercase) rather than <KeepAlive>.
KeepAlive basic usage with dynamic components
The <KeepAlive> built-in component allows conditional caching of component instances when dynamically switching between multiple components. By default, an active component instance is unmounted when switching away, causing any changed state to be lost. Wrapping a dynamic component with <KeepAlive> preserves the state across component switches by caching inactive component instances.
KeepAlive include and exclude props
The <KeepAlive> component accepts 'include' and 'exclude' props to customize which component instances are cached. Both props can be a comma-delimited string, a RegExp, or an array containing either type. The match is checked against the component's 'name' option, so components needing conditional caching must explicitly declare a name option. As of Vue 3.2.34, a single-file component using <script setup> automatically infers its name option from the filename.
KeepAlive max prop for LRU cache behavior
The <KeepAlive> component accepts a 'max' prop to limit the maximum number of cached component instances. When the number of cached instances exceeds the max count, <KeepAlive> behaves like an LRU (Least Recently Used) cache, destroying the least recently accessed cached instance to make room for the new one.
KeepAlive deactivated and activated lifecycle states
When a component instance is removed from the DOM but is part of a tree cached by <KeepAlive>, it goes into a 'deactivated' state instead of being unmounted. When a component instance is inserted into the DOM as part of a cached tree, it is 'activated'. These are distinct from the regular mount and unmount lifecycle.
activated and deactivated options lifecycle hooks
In the Options API, a kept-alive component can register lifecycle hooks using 'activated' and 'deactivated' options. activated is called on initial mount and every time the component is re-inserted from the cache. deactivated is called when removed from the DOM into the cache and also when unmounted. Both hooks work for the root component cached by <KeepAlive> and also for descendant components in the cached tree.
Disable Suspense control with suspensible false
An async component can opt-out of <Suspense> control by specifying suspensible: false in its options, allowing the component to always control its own loading state.
Suspense slots
<Suspense> has two slots: #default and #fallback. Both slots only allow for one immediate child node. The default slot is shown if possible; if not, the fallback slot is shown instead.
Suspense basic example
Basic <Suspense> usage: <Suspense><Dashboard /><template #fallback>Loading...</template></Suspense>
Suspense render states
On initial render, <Suspense> renders default slot content in memory. If async dependencies are encountered, it enters a pending state and displays fallback content. When all async dependencies are resolved, it enters a resolved state and displays the resolved default slot content. If no async dependencies are encountered, it directly goes into a resolved state.
Suspense timeout prop behavior
When reverting to pending state, fallback content is not immediately displayed. Instead, <Suspense> displays the previous #default content while waiting for new content and its async dependencies to resolve. The timeout prop controls this behavior: <Suspense> will switch to fallback content if it takes longer than timeout milliseconds to render new default content. A timeout value of 0 causes fallback content to display immediately when default content is replaced.
Suspense events
<Suspense> emits three events: pending (when entering pending state), resolve (when new content finishes resolving in default slot), and fallback (when fallback slot contents are shown). These can be used to show loading indicators while new components are loading.
Suspense error handling
<Suspense> does not provide error handling via the component itself. Use the errorCaptured lifecycle option or the onErrorCaptured() lifecycle hook to capture and handle async errors in the parent component of <Suspense>.
Suspense with Transition and KeepAlive nesting
When combining <Suspense> with <Transition> and <KeepAlive> components, the nesting order matters. Example: <RouterView v-slot="{ Component }"><template v-if="Component"><Transition mode="out-in"><KeepAlive><Suspense><component :is="Component"></component><template #fallback>Loading...</template></Suspense></KeepAlive></Transition></template></RouterView>
Vue Router lazy loading and Suspense
Vue Router has built-in support for lazily loading components using dynamic imports. These are distinct from async components and currently do not trigger <Suspense>. However, lazy-loaded routes can still have async components as descendants, and those can trigger <Suspense>.
Nested Suspense support
Nested <Suspense> components are only supported in Vue 3.3+.
Nested async component issue
When multiple async components exist (like nested or layout-based routes), changing an inner async component causes the nested component to render an empty node until resolved instead of showing the previous state or fallback slot.
Nested Suspense with suspensible prop example
To handle patching for nested async components, use a nested <Suspense> with the suspensible prop: <Suspense><component :is="DynamicAsyncOuter"><Suspense suspensible><component :is="DynamicAsyncInner" /></Suspense></component></Suspense>
Suspense revert to pending state behavior
Once resolved, <Suspense> only reverts to pending state if the root node of the #default slot is replaced. New async dependencies nested deeper in the tree will not cause revert to pending state.
Nested Suspense suspensible prop behavior
Without the suspensible prop, inner <Suspense> is treated as a sync component by parent <Suspense>, causing it to have its own fallback slot with potential empty nodes and multiple patching cycles. When suspensible is set, all async dependency handling is given to the parent <Suspense> (including events), and the inner <Suspense> serves solely as a boundary for dependency resolution and patching.
Suspense component purpose
The <Suspense> component orchestrates async dependencies in a component tree and renders a loading state while waiting for multiple nested async dependencies to be resolved.
Suspense is experimental
<Suspense> is an experimental feature and is not guaranteed to reach stable status. The API may change before it does.
Types of async dependencies Suspense waits on
<Suspense> can wait on two types of async dependencies: (1) components with an async setup() hook, including components using <script setup> with top-level await expressions, and (2) async components.
Async setup hook example
A Composition API component's setup() hook can be async. Example: export default { async setup() { const res = await fetch(...); const posts = await res.json(); return { posts }; } }
Script setup with top-level await
Using <script setup> with top-level await expressions automatically makes the component an async dependency. Example: <script setup> const res = await fetch(...); const posts = await res.json(); </script> <template>{{ posts }}</template>
Async components are suspensible by default
Async components are suspensible by default, meaning if a <Suspense> exists in the parent chain, the async component will be treated as an async dependency of that <Suspense>. The loading state will be controlled by <Suspense>, and the component's own loading, error, delay and timeout options will be ignored.
TransitionGroup animates list insertions, removals, and reordering
The <TransitionGroup> built-in component is designed for animating the insertion, removal, and order change of elements or components that are rendered in a list.
TransitionGroup doesn't render wrapper element by default
By default, <TransitionGroup> does not render a wrapper element. You can specify an element to be rendered with the tag prop.
TransitionGroup shares props and hooks with Transition
<TransitionGroup> supports the same props, CSS transition classes, and JavaScript hook listeners as <Transition>.
TransitionGroup does not support transition modes
Transition modes are not available in <TransitionGroup> because elements are not mutually exclusive.
TransitionGroup elements require unique key attribute
Elements inside <TransitionGroup> are always required to have a unique key attribute.
TransitionGroup CSS classes apply to individual elements, not container
CSS transition classes will be applied to individual elements in the list, not to the group or container itself.
TransitionGroup in-DOM template reference
When used in in-DOM templates, <TransitionGroup> should be referenced as <transition-group>.
TransitionGroup enter/leave transition example with CSS
Example of applying enter/leave transitions to a v-for list using <TransitionGroup>:
```vue-html
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item">
{{ item }}
</li>
</TransitionGroup>
```
```css
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
```
TransitionGroup move transitions CSS rule
To animate elements moving smoothly when other items are inserted or removed, add the .list-move transition class and position: absolute to .list-leave-active to take leaving items out of layout flow:
```css
.list-move,
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-leave-active {
position: absolute;
}
```
TransitionGroup moveClass prop for custom transition classes
You can specify custom transition classes for the moving element by passing the moveClass prop to <TransitionGroup>, similar to custom transition classes on <Transition>.
TransitionGroup staggering list transitions with JavaScript hooks
To stagger transitions in a <TransitionGroup> list using JavaScript hooks, render the index of an item as a data attribute on the DOM element, then use that attribute in JavaScript hooks to calculate delays:
```vue-html
<TransitionGroup
tag="ul"
:css="false"
@before-enter="onBeforeEnter"
@enter="onEnter"
@leave="onLeave"
>
<li
v-for="(item, index) in computedList"
:key="item.msg"
:data-index="index"
>
{{ item.msg }}
</li>
</TransitionGroup>
```
```js
function onEnter(el, done) {
gsap.to(el, {
opacity: 1,
height: '1.6em',
delay: el.dataset.index * 0.15,
onComplete: done
})
}
```
TransitionGroup pitfall: surrounding items jump without move transitions
When an item is inserted or removed from a <TransitionGroup> list, surrounding items instantly jump into place instead of moving smoothly if you do not apply move transitions with the .list-move CSS class and remove leaving items from layout flow.
Class-based animations with dynamic CSS classes
Trigger animations by dynamically adding or removing CSS classes to elements that are not entering or leaving the DOM. Bind the class conditionally using :class with a boolean state that controls which CSS animation class is applied.
Class-based animation example: shake effect
Example showing a disabled button with shake animation triggered by a class. The Composition API code uses ref(false) for disabled state, setting it to true in warnDisabled(), then back to false after 1500ms with setTimeout. The template binds :class="{ shake: disabled }" to the div. The CSS defines .shake with animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both and transform: translate3d(0, 0, 0). The @keyframes shake keyframe uses translate3d at 10%/90% (-1px), 20%/80% (2px), 30%/50%/70% (-4px), and 40%/60% (4px).
State-driven animations with style bindings
Apply transition effects by interpolating values and binding styles to elements during interactions. Track numerical state with ref and bind it to CSS properties via :style, which animates smoothly when the state changes.
State-driven animation example: color interpolation
Example animating a background color based on mouse position. Composition API uses const x = ref(0) and tracks clientX in onMousemove(e). Template has @mousemove="onMousemove" and :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }" on a div with class movearea. CSS adds transition: 0.3s background-color ease to smoothly animate color changes.
Animating with watchers and GSAP
Use watchers to animate any values based on numerical state changes. Combine watchers with GSAP library to create smooth transitions. Watch a numeric ref, then call gsap.to() on a reactive object to tween the value over a duration.
Watcher animation example: tweening numbers with GSAP
Example animating a number input with GSAP. Composition API imports ref, reactive, watch from vue and gsap. Creates const number = ref(0) and const tweened = reactive({ number: 0 }). In watch(number, (n) => { gsap.to(tweened, { duration: 0.5, number: Number(n) || 0 }) }). Template has <input v-model.number="number" /> and <p>{{ tweened.number.toFixed(0) }}</p>. Note: For inputs greater than Number.MAX_SAFE_INTEGER (9007199254740991), the result may be inaccurate due to JavaScript number precision limitations.
Animations beyond <Transition> and <TransitionGroup>
Vue provides Transition and TransitionGroup components for enter/leave and list transitions, but many other animation techniques are available: class-based animations, state-driven animations with style bindings, and watchers combined with animation libraries like GSAP.
Transition component basic usage
The <Transition> component is a built-in Vue component used to apply enter and leave animations on elements or components passed to it via its default slot. Animations can be triggered by conditional rendering via v-if, conditional display via v-show, dynamic components toggling via the <component> special element, or changing the special key attribute.
Transition CSS class timing
When an element in a <Transition> component is inserted or removed, Vue automatically detects CSS transitions/animations and applies six classes at appropriate timings. If no CSS transitions/animations are detected and no JavaScript hooks are provided, DOM operations occur on the browser's next animation frame.
Six transition classes
The six transition classes are: (1) v-enter-from - starting state for enter, added before insertion and removed one frame after; (2) v-enter-active - active state applied during entire entering phase, defines duration/delay/easing; (3) v-enter-to - ending state added one frame after insertion, removed when animation finishes; (4) v-leave-from - starting state for leave, added immediately when triggered, removed after one frame; (5) v-leave-active - active state applied during entire leaving phase, defines duration/delay/easing; (6) v-leave-to - ending state added one frame after leave triggered, removed when animation finishes.
Named transitions
A transition can be named using the name prop. For a named transition, transition classes are prefixed with the name instead of 'v'. For example, <Transition name="fade"> will apply classes like fade-enter-active instead of v-enter-active.
CSS Transitions with multiple properties
CSS Transitions can animate multiple properties with different durations and easing curves for enter and leave. The transition CSS property allows specifying which properties animate, duration, and easing curves. Enter and leave can have different timing.
CSS Animations with Transition component
Native CSS animations are applied the same way as CSS transitions, with the difference that *-enter-from is not removed immediately after element insertion but on an animationend event. Most CSS animations can be declared under *-enter-active and *-leave-active classes.
Custom transition classes props
Custom transition classes can be specified using props: enter-from-class, enter-active-class, enter-to-class, leave-from-class, leave-active-class, leave-to-class. These override conventional class names and are useful for combining Vue's transition system with existing CSS animation libraries like Animate.css.
Type prop for transitions and animations
When both CSS transitions and animations are on the same element, explicitly declare the type Vue should care about using the type prop with value 'animation' or 'transition'. Vue normally detects automatically whether to listen for transitionend or animationend events, but explicit declaration is needed when both are present.
Nested transitions and explicit duration
Nested transitions can use nested CSS selectors to transition elements inside the direct child. Transition delays can be added to nested elements for staggered animations. The duration prop can specify explicit transition duration in milliseconds to ensure Vue waits for all inner element transitions to finish rather than just the first transitionend event.
Transition duration prop syntax
The duration prop on <Transition> accepts a number (milliseconds) for the total duration, or an object with separate values: <Transition :duration="550"> or <Transition :duration="{ enter: 500, leave: 800 }">.
JavaScript transition hooks
JavaScript hooks available on <Transition> are: @before-enter (called before element insertion, set enter-from state), @enter (called one frame after insertion, start entering animation, call done callback to indicate end), @after-enter (when enter transition finishes), @enter-cancelled (when enter transition cancelled before completion), @before-leave (before leave starts), @leave (when leave transition starts, call done callback to indicate end), @after-leave (when leave transition finishes and element removed from DOM), @leave-cancelled (only with v-show transitions).
JavaScript-only transitions with :css="false"
When using JavaScript-only transitions, add :css="false" prop to skip auto CSS transition detection. This is slightly more performant and prevents CSS rules from accidentally interfering. With :css="false", you are fully responsible for controlling when transitions end and done callbacks are required for @enter and @leave hooks, otherwise hooks execute synchronously and transition finishes immediately.
Reusable transition components
Create reusable transitions by wrapping the built-in <Transition> component in a component that passes down slot content. The wrapper component should avoid using <style scoped> since it does not apply to slot content. This allows the transition to be imported and used like the built-in version.
Transition appear prop
Add the appear prop to <Transition appear> to apply a transition on the initial render of a node, not just on subsequent enters and leaves.