Tutorials Logic, IN info@tutorialslogic.com

Angular Animations animate.enter, animate.leave, CSS: Tutorial, Examples, FAQs & Interview Tips

Angular Animations animate.enter, animate.leave, CSS

Angular animations turn state changes into timed transitions and keyframes so UI motion feels deliberate instead of abrupt.

Focus on animation triggers, states, transitions, and the browser behaviors that make motion appear smooth or fail silently.

A strong understanding of animations should include how triggers map to states and how timing and style changes are combined.

Angular Animations animate.enter animate.leave CSS should be studied as a practical Angular lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.

In the angular > animations page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.

Angular Animations

Animations make an Angular application feel smoother and easier to understand. A good animation explains that something has entered the screen, left the screen, changed state, expanded, collapsed, loaded, or moved because of the user's action. The goal is not to decorate every element. The goal is to guide attention and make interface changes feel intentional.

Modern Angular recommends using CSS-based animations with animate.enter and animate.leave for new code. These APIs let Angular add animation classes at the right moment while CSS handles the actual motion. Older Angular projects may still use the @angular/animations package with trigger(), state(), and transition(), so this tutorial covers both approaches.

What You Should Animate

Animations should be short, purposeful, and predictable. Most UI animations work best between 120ms and 300ms. Slower animations are useful for large layout transitions, but they can make everyday actions feel delayed if overused.

  • Elements that appear or disappear, such as alerts, panels, modals, dropdowns, and list items.
  • State changes such as open/closed, selected/unselected, valid/invalid, and loading/ready.
  • Navigation or layout changes where users need help understanding what changed.
  • Small feedback moments such as button press states, focus rings, and successful form submission.

Modern Angular Approach

For new Angular applications, prefer animate.enter and animate.leave. They are compiler-supported animation bindings that work with CSS transitions or CSS keyframes. You do not need to import BrowserAnimationsModule or call provideAnimationsAsync() just to use these modern enter and leave animations.

The mental model is simple: Angular controls when the class is applied, and CSS controls how the element moves. When the animation finishes, Angular removes the temporary animation class.

This example uses modern control flow with @if. When show() becomes true, Angular adds the element to the DOM and applies the notice-enter class while the animation runs.

Basic Enter Animation

Basic Enter Animation
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-notice',
  standalone: true,
  template: `
    <button type="button" (click)="show.set(!show())">
      Toggle notice
    </button>

    @if (show()) {
      <div class="notice" animate.enter="notice-enter">
        Profile saved successfully.
      </div>
    }
  `,
  styleUrl: './notice.component.css'
})
export class NoticeComponent {
  show = signal(false);
}

Modern Angular Approach

Modern Angular Approach
.notice {
  margin-top: 12px;
  padding: 12px 14px;
  border-left: 4px solid #16a34a;
  background: #f0fdf4;
  color: #166534;
}

.notice-enter {
  animation: slide-fade-in 220ms ease-out;
}

@keyframes slide-fade-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Enter and Leave Together

Most real UI elements need both an entrance and an exit. Use animate.enter for the class that runs when the element is inserted, and animate.leave for the class that runs before Angular removes the element.

The forwards value in the leave animation keeps the final hidden style while Angular waits for the animation to finish and then removes the element from the DOM.

Toast Enter and Leave

Toast Enter and Leave
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-toast-demo',
  standalone: true,
  template: `
    <button type="button" (click)="visible.set(true)">Show toast</button>
    <button type="button" (click)="visible.set(false)">Hide toast</button>

    @if (visible()) {
      <div
        class="toast"
        animate.enter="toast-enter"
        animate.leave="toast-leave"
      >
        New message received.
      </div>
    }
  `,
  styleUrl: './toast.component.css'
})
export class ToastDemoComponent {
  visible = signal(false);
}

Enter and Leave Together

Enter and Leave Together
.toast {
  width: fit-content;
  margin-top: 12px;
  padding: 10px 14px;
  border-radius: 6px;
  background: #111827;
  color: white;
  box-shadow: 0 8px 24px rgba(15, 23, 42, .18);
}

.toast-enter {
  animation: toast-in 180ms ease-out;
}

.toast-leave {
  animation: toast-out 150ms ease-in forwards;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes toast-out {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(8px) scale(.98); }
}

Using CSS Transitions Instead of Keyframes

Keyframes are good for precise multi-step motion. CSS transitions are better for simple changes between two states. With animate.enter, the animation class can define the final state and a starting style can be provided with @starting-style.

Transition with @starting-style

Transition with @starting-style
@if (open()) {
  <section class="panel" animate.enter="panel-enter">
    <h4>Account details</h4>
    <p>This panel fades and slides into place.</p>
  </section>
}

Using CSS Transitions Instead of Keyframes

Using CSS Transitions Instead of Keyframes
.panel {
  padding: 16px;
  border: 1px solid #dbeafe;
  background: #eff6ff;
}

.panel-enter {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 180ms ease-out, transform 180ms ease-out;

  @starting-style {
    opacity: 0;
    transform: translateY(10px);
  }
}

Dynamic Animation Classes

animate.enter and animate.leave can accept a string or an expression. This is useful when a component supports different motion styles, such as sliding from the left or right depending on the action.

The matching CSS classes would define different transforms, for example translateX(-16px) for a left drawer and translateX(16px) for a right drawer.

Dynamic Animation Class

Dynamic Animation Class
import { Component, computed, signal } from '@angular/core';

@Component({
  selector: 'app-drawer',
  standalone: true,
  template: `
    <button type="button" (click)="side.set('left'); open.set(true)">Left</button>
    <button type="button" (click)="side.set('right'); open.set(true)">Right</button>
    <button type="button" (click)="open.set(false)">Close</button>

    @if (open()) {
      <aside class="drawer" [animate.enter]="enterClass()" animate.leave="drawer-leave">
        Drawer from the {{ side() }} side.
      </aside>
    }
  `
})
export class DrawerComponent {
  open = signal(false);
  side = signal<'left' | 'right'>('left');
  enterClass = computed(() => this.side() === 'left' ? 'drawer-left' : 'drawer-right');
}

Animating Lists

Lists are one of the best places to use animations because adding and removing rows can otherwise feel abrupt. With modern Angular, use @for for rendering and animate.enter / animate.leave on each repeated item.

List Item Animation

List Item Animation
import { Component, signal } from '@angular/core';

type Task = { id: number; title: string };

@Component({
  selector: 'app-tasks',
  standalone: true,
  template: `
    <button type="button" (click)="addTask()">Add task</button>

    <ul class="task-list">
      @for (task of tasks(); track task.id) {
        <li class="task" animate.enter="task-enter" animate.leave="task-leave">
          <span>{{ task.title }}</span>
          <button type="button" (click)="removeTask(task.id)">Done</button>
        </li>
      } @empty {
        <li class="empty">No tasks left.</li>
      }
    </ul>
  `,
  styleUrl: './tasks.component.css'
})
export class TasksComponent {
  private nextId = 3;
  tasks = signal<Task[]>([
    { id: 1, title: 'Create animation classes' },
    { id: 2, title: 'Keep transitions short' }
  ]);

  addTask() {
    this.tasks.update(items => [
      ...items,
      { id: this.nextId, title: `Task ${this.nextId++}` }
    ]);
  }

  removeTask(id: number) {
    this.tasks.update(items => items.filter(task => task.id !== id));
  }
}

Animating Lists

Animating Lists
.task-list {
  display: grid;
  gap: 8px;
  padding: 0;
  list-style: none;
}

.task {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
}

.task-enter {
  animation: task-in 180ms ease-out;
}

.task-leave {
  animation: task-out 140ms ease-in forwards;
}

@keyframes task-in {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: translateX(0); }
}

@keyframes task-out {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(10px); }
}

Animating State Changes with CSS Classes

Not every animation needs animate.enter or animate.leave. If an element remains in the DOM and only changes state, use class binding, style binding, or CSS transitions.

This is often the cleanest approach for accordions, menus, badges, and validation states because Angular only needs to toggle a class.

Open and Closed State

Open and Closed State
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-accordion',
  standalone: true,
  template: `
    <button type="button" (click)="open.update(value => !value)">
      Toggle details
    </button>

    <div class="details" [class.details-open]="open()">
      <p>This content expands with a CSS transition.</p>
    </div>
  `,
  styleUrl: './accordion.component.css'
})
export class AccordionComponent {
  open = signal(false);
}

Animating State Changes with CSS Classes

Animating State Changes with CSS Classes
.details {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 240ms ease, opacity 180ms ease;
}

.details-open {
  max-height: 160px;
  opacity: 1;
}

Accessibility and Reduced Motion

Animations should respect users who prefer reduced motion. CSS makes this straightforward with the prefers-reduced-motion media query. In reduced-motion mode, keep important visual state changes but remove large movement and long animation durations.

Reduced Motion CSS

Reduced Motion CSS
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

Performance Best Practices

  • Prefer animating opacity and transform. They are usually cheaper than animating layout properties.
  • Avoid animating width, height, top, left, and large shadows on many elements at once.
  • Keep animations short and avoid long chains of delayed motion in everyday workflows.
  • Make sure the final UI state is clear even when animations are disabled.
  • Use stable track expressions in @for lists so Angular can animate the correct item.

Legacy Angular Animations Package

Older Angular tutorials and many existing projects use the @angular/animations package. In this model, animations are written in TypeScript using trigger(), state(), style(), animate(), and transition(). Angular has deprecated this package for new animation work, but understanding it is still useful when maintaining older apps.

If an existing app still uses this package, standalone applications typically enable it with provideAnimationsAsync() in application configuration. NgModule-based applications often use BrowserAnimationsModule.

Enable Legacy Animations

Enable Legacy Animations
import { ApplicationConfig } from '@angular/core';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideAnimationsAsync()
  ]
};

Legacy Trigger Example

Legacy Trigger Example
import { Component, signal } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';

@Component({
  selector: 'app-expand-card',
  standalone: true,
  animations: [
    trigger('expandCollapse', [
      state('open', style({
        height: '*',
        opacity: 1
      })),
      state('closed', style({
        height: '0',
        opacity: 0,
        overflow: 'hidden'
      })),
      transition('open <=> closed', [
        animate('220ms ease-in-out')
      ])
    ])
  ],
  template: `
    <button type="button" (click)="open.update(value => !value)">
      Toggle card
    </button>

    <section [@expandCollapse]="open() ? 'open' : 'closed'">
      <p>This uses the legacy Angular animations package.</p>
    </section>
  `
})
export class ExpandCardComponent {
  open = signal(false);
}

Legacy Animation States

The legacy package uses state expressions to decide which transition should run. These are common expressions you will see in existing Angular code:

  • open => closed runs only when the state changes from open to closed.
  • open <=> closed runs in both directions.
  • * is the wildcard state and matches any state.
  • void means the element is not currently in the DOM.
  • :enter is a shortcut for void => *.
  • :leave is a shortcut for * => void.

When to Use Which Approach

Need Recommended approach
Element appears or disappears animate.enter and animate.leave
Simple hover, focus, selected, or expanded state CSS transitions with Angular class binding
Repeated list item insertion/removal @for with animate.enter / animate.leave on each item
Maintaining older trigger/state code Legacy @angular/animations APIs
Complex timeline or physics animation CSS keyframes or a dedicated animation library

Summary

In modern Angular, start with CSS and use animate.enter and animate.leave when Angular needs to coordinate DOM insertion or removal. Use normal class bindings and CSS transitions for elements that remain on the page and only change state. Learn the older @angular/animations trigger syntax so you can maintain existing code, but prefer the modern CSS-based approach for new Angular applications.

Angular Animations animate.enter animate.leave CSS state check

Angular Animations animate.enter animate.leave CSS state check
const state = { topic: "Angular Animations animate.enter animate.leave CSS", ready: true };
if (state.ready) {
  console.log(state.topic + ": render or run the normal path");
}

Angular Animations animate.enter animate.leave CSS fallback check

Angular Animations animate.enter animate.leave CSS fallback check
const response = null;
const message = response?.message ?? "Angular Animations animate.enter animate.leave CSS: show a clear fallback";
console.log(message);
Key Takeaways
  • Explain the purpose of animations before memorizing syntax.
  • Run or trace one small Angular example and confirm the output.
  • Test one normal case, one edge case, and one mistake case for animations.
  • Write the rule in your own words after checking the example.
  • Connect animations to a real project scenario instead of treating it as an isolated definition.
Common Mistakes to Avoid
WRONG Memorizing Angular Animations animate.enter animate.leave CSS without the situation where it is useful.
RIGHT Connect Angular Animations animate.enter animate.leave CSS to a concrete Angular task.
Purpose makes syntax easier to recall.
WRONG Testing Angular Animations animate.enter animate.leave CSS only with the perfect input.
RIGHT Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Real bugs usually appear outside the perfect path.
WRONG Changing code before reading the visible symptom or error message.
RIGHT Inspect the output, state, configuration, or stack trace connected to Angular Animations animate.enter animate.leave CSS.
Evidence keeps debugging focused.
WRONG Memorizing Angular Animations animate.enter animate.leave CSS without the situation where it is useful.
RIGHT Connect Angular Animations animate.enter animate.leave CSS to a concrete Angular task.
Purpose makes syntax easier to recall.

Practice Tasks

  • Modify the example so it handles a different input or condition.
  • Write one mistake related to animations, then fix it and explain the fix.
  • Summarize when to use animations and when another approach is better.
  • Write a small example that uses Angular Animations animate.enter animate.leave CSS in a realistic Angular scenario.
  • Change one important value in the Angular Animations animate.enter animate.leave CSS example and predict the result first.

Frequently Asked Questions

No. For modern <code>animate.enter</code> and <code>animate.leave</code> animations, write CSS classes and bind them in the template. <code>BrowserAnimationsModule</code> and <code>provideAnimationsAsync()</code> are used for the older <code>@angular/animations</code> package.

<code>animate.enter</code> applies an animation class when Angular inserts an element into the DOM. <code>animate.leave</code> applies an animation class before Angular removes the element from the DOM.

Use CSS transitions for simple before-and-after state changes. Use keyframes when the motion needs named stages, a custom path, or more precise timing.

Yes, if you maintain older Angular applications. Many real projects still use <code>trigger()</code>, <code>state()</code>, and <code>transition()</code>, so recognizing the syntax is practical even though new code should usually prefer the modern CSS-based approach.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.