We use cookies to enhance your experience on the site
CodeWorlds

Animations in Angular

Animations are like fluid movements in kata - choreography that brings the application to life.

Configuration

1// app.config.ts
2import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
3
4export const appConfig: ApplicationConfig = {
5  providers: [
6    provideAnimationsAsync()  // Lazy loading of animations
7  ]
8};

Basic Animations

1import {
2  trigger,
3  transition,
4  style,
5  animate,
6  state,
7  query,
8  stagger,
9  keyframes,
10  group
11} from '@angular/animations';
12
13@Component({
14  selector: 'app-samurai-list',
15  animations: [
16    // Fade in/out
17    trigger('fadeInOut', [
18      transition(':enter', [
19        style({ opacity: 0, transform: 'translateY(-20px)' }),
20        animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
21      ]),
22      transition(':leave', [
23        animate('200ms ease-in', style({ opacity: 0, transform: 'translateY(20px)' }))
24      ])
25    ]),
26
27    // Active/inactive state
28    trigger('activeState', [
29      state('inactive', style({
30        transform: 'scale(1)',
31        opacity: 0.8
32      })),
33      state('active', style({
34        transform: 'scale(1.05)',
35        opacity: 1,
36        boxShadow: '0 4px 20px rgba(0,0,0,0.2)'
37      })),
38      transition('inactive <=> active', animate('200ms ease-in-out'))
39    ]),
40
41    // List with stagger effect
42    trigger('listAnimation', [
43      transition('* => *', [
44        query(':enter', [
45          style({ opacity: 0, transform: 'translateX(-50px)' }),
46          stagger('50ms', [
47            animate('300ms ease-out', style({ opacity: 1, transform: 'translateX(0)' }))
48          ])
49        ], { optional: true })
50      ])
51    ])
52  ],
53  template: \`
54    <div [@listAnimation]="samuraiList().length">
55      @for (samurai of samuraiList(); track samurai.id) {
56        <div
57          class="samurai-card"
58          [@fadeInOut]
59          [@activeState]="samurai.id === selectedId() ? 'active' : 'inactive'"
60          (click)="select(samurai.id)"
61        >
62          {{ samurai.name }}
63        </div>
64      }
65    </div>
66  \`
67})
68export class SamuraiListComponent {
69  samuraiList = signal<Samurai[]>([]);
70  selectedId = signal<number | null>(null);
71
72  select(id: number): void {
73    this.selectedId.set(id);
74  }
75}

Keyframe Animations

1trigger('attack', [
2  transition('* => attacking', [
3    animate('500ms', keyframes([
4      style({ transform: 'translateX(0)', offset: 0 }),
5      style({ transform: 'translateX(100px) rotate(45deg)', offset: 0.5 }),
6      style({ transform: 'translateX(0)', offset: 1 })
7    ]))
8  ])
9])

Group Animations

1trigger('cardFlip', [
2  transition('front => back', [
3    group([
4      animate('300ms', style({ transform: 'rotateY(180deg)' })),
5      query('.front', animate('300ms', style({ opacity: 0 }))),
6      query('.back', animate('300ms', style({ opacity: 1 })))
7    ])
8  ])
9])
Go to CodeWorlds