Skip to content

Angular Animations Explained — Create Smooth UI Animations

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Angular Animations Explained. We cover key concepts, practical examples, and best practices to help you master this topic.

Angular animations let you create smooth transitions between visual states using a declarative DSL based on CSS transitions and Web Animations API.

What You'll Learn

  • The Angular animation DSL: trigger, state, transition, animate
  • How to animate between states with style and keyframes
  • How to orchestrate multi-element animations with query and stagger
  • How to use animation callbacks
  • Performance best practices for Angular animations

Why It Matters

Animations improve user experience by providing visual feedback, guiding attention, and making state changes feel natural. In security tools like Durga Antivirus Pro, animations signal scan progress, threat alerts, and status changes without requiring the user to read text.

Real-World Use

Durga Antivirus Pro uses a pulsing animation on the scan button when a scan is in progress, a slide-in animation for threat alerts, and a counter animation that transitions threat numbers smoothly.

flowchart LR
    A[Trigger Event] --> B[Animation Trigger]
    B --> C[State A]
    B --> D[State B]
    C -->|transition| D
    D -->|transition| C
    style A fill:#f97316,color:#fff

Setting Up Animations

Import provideAnimations and define animations in the component:

import { Component } from "@angular/core";
import { trigger, state, style, transition, animate } from "@angular/animations";

@Component({
  selector: "app-fade-box",
  standalone: true,
  template: `
    <button (click)="toggle()">Toggle</button>
    <div @fadeInOut class="box" *ngIf="visible">
      <p>I fade in and out</p>
    </div>
  `,
  styles: [`
    .box { background: #f97316; color: white; padding: 20px; border-radius: 8px; width: 200px; text-align: center; }
  `],
  animations: [
    trigger("fadeInOut", [
      transition(":enter", [
        style({ opacity: 0, transform: "scale(0.8)" }),
        animate("300ms ease-out", style({ opacity: 1, transform: "scale(1)" }))
      ]),
      transition(":leave", [
        animate("300ms ease-in", style({ opacity: 0, transform: "scale(0.8)" }))
      ])
    ])
  ]
})
export class FadeBoxComponent {
  visible = true;
  toggle() { this.visible = !this.visible; }
}

Expected output: The box fades and scales in when it appears, and fades and scales out when it disappears.

The :enter and :leave aliases handle element insertion and removal. The trigger binds the animation to the template with @fadeInOut.

State-Based Animations

Animate between defined states:

import { Component } from "@angular/core";
import { trigger, state, style, transition, animate } from "@angular/animations";

@Component({
  selector: "app-expandable",
  standalone: true,
  template: `
    <button (click)="toggle()">{{ expanded ? 'Collapse' : 'Expand' }}</button>
    <div @expandCollapse class="content" style="overflow:hidden">
      <p>This content expands and collapses smoothly.</p>
      <p>Additional details appear here when expanded.</p>
      <p>Angular animations handle the height transition.</p>
    </div>
  `,
  animations: [
    trigger("expandCollapse", [
      state("collapsed", style({ height: "0", opacity: 0, padding: "0 16px" })),
      state("expanded", style({ height: "*", opacity: 1, padding: "16px" })),
      transition("collapsed <=> expanded", animate("300ms ease-in-out"))
    ])
  ]
})
export class ExpandableComponent {
  expanded = false;
  toggle() { this.expanded = !this.expanded; }
}

Expected output: The content expands and collapses smoothly when the button is clicked.

* in style means "the current computed value". The <=> syntax creates a two-way transition. Angular automatically detects the actual height of the element at runtime.

Keyframe Animations

Define multi-step animations with keyframes:

import { Component } from "@angular/core";
import { trigger, transition, style, animate, keyframes } from "@angular/animations";

@Component({
  selector: "app-bounce",
  standalone: true,
  template: `
    <button (click)="bounce()">Bounce</button>
    <div @bounce *ngIf="bouncing" style="background:#f97316;color:white;padding:20px;border-radius:8px;width:150px;text-align:center"
      (@bounce.done)="bouncing = false">
      <p>Bounce!</p>
    </div>
  `,
  animations: [
    trigger("bounce", [
      transition("void => *", [
        animate("600ms ease-out", keyframes([
          style({ transform: "scale(0)", offset: 0 }),
          style({ transform: "scale(1.2)", offset: 0.4 }),
          style({ transform: "scale(0.9)", offset: 0.6 }),
          style({ transform: "scale(1.05)", offset: 0.8 }),
          style({ transform: "scale(1)", offset: 1 }),
        ]))
      ])
    ])
  ]
})
export class BounceComponent {
  bouncing = false;
  bounce() {
    this.bouncing = false;
    setTimeout(() => this.bouncing = true);
  }
}

Expected output: The element bounces in with a spring-like effect when triggered.

Keyframes let you define multiple intermediate styles at different offsets (0 to 1). Each offset represents the percentage of the animation duration. This is more expressive than simple from / to transitions.

Group and Sequence

Run animations in parallel with group or sequentially with sequence:

import { trigger, transition, style, animate, group, sequence } from "@angular/animations";

// Group runs all child animations simultaneously
transition(":enter", [
  group([
    animate("300ms", style({ transform: "translateX(0)" })),
    animate("500ms", style({ opacity: 1 })),
  ])
])

// Sequence runs child animations one after another
transition(":leave", [
  sequence([
    animate("200ms", style({ color: "red" })),
    animate("300ms", style({ transform: "translateX(100%)" })),
    animate("200ms", style({ opacity: 0 })),
  ])
])

Expected output: Grouped animations run in parallel; sequenced animations run one after the other.

group is useful for complex entrances where multiple properties animate independently. sequence is useful for multi-step exits where each step must complete before the next starts.

Query and Stagger

Animate multiple child elements with query and stagger:

import { trigger, transition, style, animate, query, stagger } from "@angular/animations";

trigger("listAnimation", [
  transition(":enter", [
    query("li", [
      style({ opacity: 0, transform: "translateX(-20px)" }),
      stagger("50ms", [
        animate("300ms ease-out", style({ opacity: 1, transform: "translateX(0)" }))
      ])
    ])
  ])
])

Usage in template:

<ul @listAnimation>
  <li *ngFor="let item of items">{{ item }}</li>
</ul>

Expected output: List items animate in one by one from left to right with a 50ms stagger delay between each.

query finds child elements matching the selector. stagger adds a delay between animations of matched elements. This creates a cascading effect that looks more polished than animating all items simultaneously.

Common Mistakes

  1. Missing BrowserAnimationsModule or provideAnimations — Without importing provideAnimations in the providers, animations will not run and Angular throws errors.

  2. Animating non-animatable properties — CSS properties like display cannot be animated. Use opacity and transform instead for smooth animations.

  3. Overusing animations — Too many simultaneous animations hurt performance and user experience. Animate only state changes that benefit from visual feedback.

  4. Forgetting void state for enter/leave — The :enter transition goes from void to *. Explicit void styles ensure the initial state is correct before the animation starts.

  5. Animating layout properties — Animating width, height, top, left triggers layout recalculations. Prefer transform and opacity for GPU-accelerated animations.

Practice Questions

  1. What is a trigger in Angular animations? A trigger defines an animation that can be bound to in the template using the @triggerName syntax.

  2. What is the difference between state and transition? A state defines a fixed set of styles. A transition defines how to animate between two states.

  3. What does :enter and :leave represent? :enter fires when an element is added to the DOM. :leave fires when an element is removed.

  4. How do you run animations in parallel? Use the group() function to run multiple child animations simultaneously.

  5. What is the stagger function used for? It adds a delay between animations of matched child elements, creating a cascading effect.

Challenge

Build a NotificationListComponent that displays notifications that slide in from the right (entrance), stack with stagger, and slide out to the left (exit). Each notification auto-dismisses after 5 seconds with a fade-out animation. Use query and stagger for the list entrance.

FAQ

Are Angular animations CSS or JavaScript?

They are a TypeScript DSL that generates Web Animations API calls or CSS transitions automatically.

Can I use CSS animations instead of Angular animations?

Yes, but Angular animations integrate with change detection and provide features like stagger, query, and animation callbacks.

Do animations affect performance?

Poorly written animations can cause jank. Use transform and opacity, avoid layout-triggering properties, and use will-change.

How do I disable animations during testing?

Use provideNoopAnimations() instead of provideAnimations() in the test providers.

Can I reuse animations across components?

Yes, export the animation definitions and use them in multiple components.

Mini Project

Build a SlideShowComponent with animated transitions between slides. Support fade, slide-left, and slide-right transitions. Use query and group to animate the current slide out while the next slide animates in. Add navigation buttons and Auto-Play with a timer. Use animation callbacks to sync the auto-play timer with the animation duration.

What's Next

Continue with reactive forms and form validation:

Angular Forms Reactive, Angular Forms Validation, Angular Components

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro