Skip to content
Documentation/Animate on enter and leave

Search documentation

Type to search the documentation.

Guides

Animate on enter and leave

Animate an element when Angular creates it, shape the timing, and let it finish leaving before it is removed.

Use MoveEnterDirective when an element should animate once, as Angular creates it: a card that fades up, a toast that slides in, a heading that rises. This is the smallest useful piece of Angular Movement.

Animate an element when it enters

card.ts
@Component({
  selector: 'app-card',
  imports: [MoveEnterDirective],
  template: `<article moveEnter="fade-up">Billing summary</article>`,
})
export class Card {}

View source

moveEnter takes a preset name or your own keyframes. It runs once, when the directive initialises, and ignores later input changes. That is by design: it describes an entrance, not a state. To animate between states when a signal changes, use reactive animation and variants.

moveEnter

The real directive. moveEnter plays once when the element is created, so each change recreates the element to replay it.

fade-up

entered 1×

Inputs

Events

No events yet. Interact with the preview to see them here.

Template

<div
  moveEnter="fade-up"
  [moveDuration]="500"
  [moveDelay]="0"
  moveEasing="ease-out"
>Content</div>

moveEnter — expanded preview

The playground wraps the directive in a small component. Because moveEnter is init-only, changing a control (or pressing Replay) recreates the element, which plays the animation again — the page is not pretending the directive is reactive. Open the full playground for every preset.

Shape the timing

Duration, delay and easing are plain inputs shared by every directive. A bare number is milliseconds; a string states its unit.

toast.ts
@Component({
  selector: 'app-toast',
  imports: [MoveEnterDirective],
  template: `
    <div moveEnter="slide-up" moveDuration="300ms" moveDelay="100ms" moveEasing="ease-out">
      Saved
    </div>
  `,
})
export class Toast {}

View source

Defaults for the whole app come from provideMovement; the input on the element always wins.

Use your own keyframes

Presets are shorthand for keyframes. Pass an object to animate anything the Web Animations API can animate — keyframes are typed for the common shorthands (x, y, scale, rotate, blur, opacity, …) and any other CSS property passes straight through.

wipe.ts
@Component({
  selector: 'app-wipe',
  imports: [MoveEnterDirective],
  template: `
    <!-- Any CSS property the Web Animations API can animate, not just presets. -->
    <div [moveEnter]="{ clipPath: ['inset(0 100% 0 0)', 'inset(0 0% 0 0)'] }">Wipe</div>
    <div [moveEnter]="{ opacity: [0, 1], y: [16, 0] }" moveDuration="400ms">Rise</div>
  `,
})
export class Wipe {}

View source

Let an element finish leaving

MoveLeaveDirective describes an exit, but it cannot hold a node that Angular has already removed. @if destroys its view synchronously, so there is nothing left to animate. Wrap the content in *movePresence, which keeps the view in the DOM until every leave animation inside it has finished:

details.ts
@Component({
  selector: 'app-details',
  imports: [MovePresenceDirective, MoveEnterDirective, MoveLeaveDirective],
  template: `
    <button type="button" (click)="open.set(!open())">Toggle</button>

    <ng-container *movePresence="open()">
      <aside moveEnter="fade-up" moveLeave="fade-down">Details</aside>
    </ng-container>
  `,
})
export class Details {
  protected readonly open = signal(false);
}

View source

See Presence for the full model, including keyed lists.

[move] and moveAnimate

MoveAnimateDirective ([move], [moveAnimate]) is the shorthand for an entrance plus an exit on one element, with moveInitial and moveExit states. Like moveEnter it is one-shot.

hero-title.ts
@Component({
  selector: 'app-hero-title',
  imports: [MoveAnimateDirective],
  template: `<h1 [moveInitial]="{ opacity: 0, y: 24 }" [moveAnimate]="{ opacity: 1, y: 0 }">
    Hi
  </h1>`,
})
export class HeroTitle {}

View source

Limits to know

  • Both directives are no-ops on the server and start after hydration. For an above-the-fold entrance that must paint before the app boots, use CSS; see Accessibility and troubleshooting.
  • Reduced motion jumps straight to the end state automatically.
  • Unsure which directive to pick? Choose an API.

Related: moveEnter playground · moveLeave playground · moveAnimate playground · MoveEnterDirective