In Angular, how do you slide a toast notification in and out with animate.enter and animate.leave when an @if block toggles it?
answer
- compiler-supported, not a directive
- class added on insertion
- removal waits for the animation
- classes present only while animating
basics
~20 sPut animate.enter="toast-in" and animate.leave="toast-out" on the toast element inside @if. Angular adds the enter class when the element is inserted and removes it afterwards; on removal it adds the leave class and keeps the element until that animation ends.
solid answer
~40 s`animate.enter` and `animate.leave` are template syntax the Angular compiler understands directly, so nothing has to be imported or provided. On the toast element inside `@if (visible())` I write `animate.enter="toast-in"` and `animate.leave="toast-out"`, and define those classes in CSS with a keyframe animation or a transition. When the condition becomes true, Angular inserts the element, adds `toast-in`, and takes the class off again once the longest animation on the element finishes. When the condition becomes false, Angular adds `toast-out` and keeps the element in the DOM until that animation ends, then removes it. Both accept a space-separated string, an array of classes, or a bound expression such as `[animate.leave]="exitClass()"`. This is the recommended API since v20.2, when `@angular/animations` was deprecated.
code
ts · 28 linesimport {Component, signal} from '@angular/core';
@Component({
selector: 'app-toast-host',
template: `
<button type="button" (click)="notify()">Save</button>
@if (visible()) {
<div class="toast" role="status" animate.enter="toast-in" animate.leave="toast-out">
Changes saved
</div>
}
`,
styles: `
.toast { position: fixed; right: 16px; bottom: 16px; }
.toast-in { animation: toast-slide-in 250ms ease-out; }
.toast-out { animation: toast-slide-out 200ms ease-in; }
@keyframes toast-slide-in { from { transform: translateY(120%); opacity: 0; } }
@keyframes toast-slide-out { to { transform: translateY(120%); opacity: 0; } }
`,
})
export class ToastHost {
protected readonly visible = signal(false);
notify(): void {
this.visible.set(true);
setTimeout(() => this.visible.set(false), 3000);
}
}go deeper
Recall the syntax: animate.enter and animate.leave on an element inside @if or @for, each naming CSS classes. Say that no import is needed and that removal waits for the leave animation.
Explain the lifecycle of the classes: added on insertion, removed after the longest animation, and the leave class delaying removal. Mention the binding forms and that transitions need @starting-style.
Show judgment about where motion lives: CSS classes in the stylesheet, host bindings for reusable components, and a plan for codebases still on @angular/animations triggers, which cannot share a component with the new API.
Frame the choice as removing a runtime animation engine in favour of the platform: smaller bundles and browser-driven motion, traded against losing the old DSL's cross-component orchestration.
## What the two features are Angular has two template features for animating an element as it is added to or removed from the page: - **`animate.enter`** applies one or more CSS classes to an element at the moment Angular inserts it into the DOM, and takes them off again when the animation they start has finished. - **`animate.leave`** applies one or more CSS classes to an element at the moment Angular would remove it, and **delays the physical removal** until the animation those classes start has finished. They are **not directives**. The Angular compiler recognises the `animate.enter` and `animate.leave` names itself and generates dedicated instructions for them, so a standalone component does not add anything to its `imports` array and the application does not need an animations provider. They arrived in **Angular 20.2**, the same release that deprecated the `@angular/animations` package, and they are the current recommendation for new code in Angular 22. ## The toast, step by step A toast is the textbook case: it appears at the edge of the screen, stays for a few seconds, and disappears. Angular's built-in control flow decides when it exists; the two animation features decide how it arrives and leaves. 1. The signal `visible` becomes `true`, so the `@if` block creates its view and inserts the toast element. 2. Angular adds the `animate.enter` class (say `toast-in`). Its CSS starts a keyframe animation that slides the toast up from below. 3. Angular listens for the animation's end on that element. When the **longest** running animation or transition finishes, it removes `toast-in`. The class exists only while the animation runs. 4. Later `visible` becomes `false`. Instead of detaching the element straight away, Angular adds the `animate.leave` class (`toast-out`). 5. When the longest leave animation ends, Angular removes the element from the DOM. The base `.toast` rule describes the toast at rest. The enter and leave classes only describe motion, which is why they can be removed afterwards without the toast changing. ## The value you can bind | Form | Example | Use it when | |---|---|---| | Static string | `animate.enter="toast-in"` | the class never changes | | Several classes | `animate.leave="toast-out fade"` | combining utility classes | | Property binding | `[animate.leave]="exitClass()"` | the class depends on state, for example the toast's position | | Array | `[animate.enter]="['toast-in', 'shadow-pop']"` | building the list in code | | Event binding | `(animate.leave)="slideOut($event)"` | a JavaScript function or an animation library does the motion | The same names also work as **host bindings** (`host: {'animate.leave': 'toast-out'}`), which lets a toast component describe its own entrance and exit. ## Keyframes versus transitions A **keyframe animation** carries its own start and end values, so an `animate.enter` class that sets `animation: toast-slide-in 250ms` works on its own. A **transition** is different: it only animates from one computed value to another. The class that `animate.enter` adds describes the state to animate *to*, so the element also needs a CSS `@starting-style` block that supplies the state to animate *from*. Without it, the element is created already in its final state and nothing visible happens. ## What interviewers probe - **Where the element goes during a leave.** It stays in the DOM, and in its normal place in the layout, until the leave animation ends. Code that queries the DOM right after flipping the signal still finds it. - **Several animations on one element.** Angular waits for the longest one, not the first one to finish. - **No animation at all.** If the class turns out not to animate anything, Angular does not wait: it removes the enter class, or the element, straight away. - **Legacy code.** Codebases still using `@angular/animations` triggers cannot mix them with `animate.enter` and `animate.leave` in the same component; the two systems can coexist in the same application, one component at a time. - **Server rendering.** On the server these instructions do nothing; the animation only runs in the browser. ## Common mistakes with a toast 1. **Styling the resting state inside the enter class.** Because the enter class is removed afterwards, anything that must stay (position, colour, shadow) belongs on the base `.toast` rule, not on `toast-in`. 2. **Hiding with a class instead of removing.** Toggling a `hidden` class never triggers `animate.leave`; only removing the element, for example with `@if`, `@for`, `@switch` or a `ViewContainerRef`, does. 3. **Expecting the old element to vanish instantly.** During the exit the toast still occupies the DOM, so a test or a query that runs immediately after `visible.set(false)` still sees it. For new code, `animate.enter` and `animate.leave` with plain CSS keep the animation in the stylesheet, where it belongs, and leave the component class free of animation state.
- Does animate.enter also play for an element that is not inside @if or @for?Yes. The enter animation runs whenever Angular creates the element. For an element written directly in a template, that is when the component's view is created, for example when the component itself first renders. Control flow is simply the usual way elements are inserted and removed later, which is why toasts and lists are the common examples.
- Can a toast component declare its own entrance and exit instead of every parent repeating the classes?Yes. `animate.enter` and `animate.leave` work as host bindings, for example `host: {'animate.enter': 'toast-in', 'animate.leave': 'toast-out'}` in the toast component's decorator. When a parent's `@if` or `@for` inserts or removes `<app-toast>`, the classes are applied to the host element, so every usage animates the same way without the parent knowing about it.
A stage manager who lets an actor finish the exit walk before closing the curtain on that part of the stage: the actor (the element) is still visible while walking off, and the curtain (removal) only drops once the walk is over.
saying these in an interview costs you the question
- You must import an animations module or provider to use animate.enter.
- animate.leave plays the animation after the element has already been removed.
- The enter class stays on the element permanently after it has animated in.
- animate.enter and animate.leave are directives from @angular/common.
- A transition class in animate.enter animates without any starting style.