Skip to content
Documentation/Reactive animation and variants

Search documentation

Type to search the documentation.

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.

card-state.ts
@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);
}

View source

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.

selectable.ts
@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);
}

View source

moveVariants

Variants are reactive: change the active name and the element animates to that state.

idle

Active variant

Inputs

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>

moveVariants — expanded preview

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)