Guides
Reactive animation and variants
Animate an element between states whenever a signal changes, with a single target or with named variants.
moveEnter plays once. When an element should move between states — selected, expanded, loading, in error — bind the state and let the animation follow it. There are two reactive APIs; both are stable.
One element, one computed target: moveAnimation
MoveAnimationDirective takes a single initial, animate and exit state and animates whenever animate changes. It compares the state by value, so an object literal in the template does not replay on every change-detection pass. Only properties present in both initial and animate are animated.
@Component({
selector: 'app-card-state',
imports: [MoveAnimationDirective],
template: `
<button type="button" (click)="open.set(!open())">Toggle</button>
<div
[moveAnimation]="{
initial: { opacity: 0.6, scale: 0.98 },
animate: open() ? { opacity: 1, scale: 1 } : { opacity: 0.6, scale: 0.98 },
}"
>
Card
</div>
`,
})
export class CardState {
protected readonly open = signal(false);
}
Named states: moveVariants
Use MoveVariantsDirective when states have names, a whole subtree shares the active variant, or you want staggerChildren and delayChildren. Set the active variant with moveVariant.
@Component({
selector: 'app-selectable',
imports: [MoveVariantsDirective],
template: `
<div
[moveVariants]="{
idle: { scale: 1, rotate: 0 },
active: { scale: 1.08, rotate: 4 },
}"
[moveVariant]="selected() ? 'active' : 'idle'"
moveDuration="200ms"
>
Card
</div>
`,
})
export class Selectable {
protected readonly selected = signal(false);
}
moveVariants
Variants are reactive: change the active name and the element animates to that state.
idle
Active variant
Template
<div
[moveVariants]="{
idle: { scale: 1, rotate: 0, opacity: 1 },
active: { scale: 1.1, rotate: 4, opacity: 1 },
error: { scale: 0.94, rotate: -3, opacity: 0.55 }
}"
moveVariant="idle"
[moveDuration]="300"
>
Card
</div>Warning
On a host with moveVariants, set the state with moveVariant (or its alias moveActiveVariant) — not moveAnimate, which moveVariants takes over.
Which one?
| You have… | Use |
|---|---|
| One element and a computed target | moveAnimation |
| Named states, shared by a subtree | moveVariants |
| A boolean that plays forward and reverses | moveTarget (experimental) |
Choose an API has the full comparison, including which directives are one-shot.
Related: moveAnimation playground · moveVariants playground · moveTarget playground (experimental)