Advanced functions for creating complex animations by combining multiple animation steps in parallel or sequence, and for querying and manipulating child elements.
Runs multiple animation steps in parallel (simultaneously).
/**
* Defines animation steps to run in parallel
* @param steps - Array of animation metadata to execute simultaneously
* @param options - Optional timing and parameter configuration
* @returns AnimationGroupMetadata for parallel execution
*/
function group(
steps: AnimationMetadata[],
options?: AnimationOptions | null
): AnimationGroupMetadata;
interface AnimationGroupMetadata extends AnimationMetadata {
steps: AnimationMetadata[];
options: AnimationOptions | null;
}Usage Examples:
import { group, animate, style } from '@angular/animations';
// Animate multiple properties simultaneously
const parallelAnimation = group([
animate('300ms', style({ opacity: 0 })),
animate('300ms', style({ transform: 'translateX(100px)' })),
animate('300ms', style({ backgroundColor: 'red' }))
]);
// Different timings in parallel
const staggeredGroup = group([
animate('200ms', style({ opacity: 0 })), // Fastest
animate('400ms', style({ transform: 'scale(0)' })), // Medium
animate('600ms', style({ color: 'blue' })) // Slowest
]);Runs multiple animation steps one after another (sequentially).
/**
* Defines animation steps to run in sequence
* @param steps - Array of animation metadata to execute sequentially
* @param options - Optional timing and parameter configuration
* @returns AnimationSequenceMetadata for sequential execution
*/
function sequence(
steps: AnimationMetadata[],
options?: AnimationOptions | null
): AnimationSequenceMetadata;
interface AnimationSequenceMetadata extends AnimationMetadata {
steps: AnimationMetadata[];
options: AnimationOptions | null;
}Usage Examples:
import { sequence, animate, style } from '@angular/animations';
// Multi-step sequential animation
const sequentialAnimation = sequence([
animate('200ms', style({ transform: 'translateY(-10px)' })), // Step 1
animate('300ms', style({ opacity: 0.5 })), // Step 2
animate('200ms', style({ transform: 'translateY(0)', opacity: 1 })) // Step 3
]);
// Complex entrance sequence
const entranceSequence = sequence([
style({ opacity: 0, transform: 'scale(0.8)' }), // Initial state
animate('150ms ease-out', style({ opacity: 1 })), // Fade in
animate('200ms cubic-bezier(0.68, -0.55, 0.265, 1.55)',
style({ transform: 'scale(1)' })) // Scale with bounce
]);Finds inner elements and applies animations to them.
/**
* Queries child elements and applies animations
* @param selector - CSS selector to find child elements
* @param animation - Animation to apply to found elements
* @param options - Optional query configuration and timing
* @returns AnimationQueryMetadata for child element animation
*/
function query(
selector: string,
animation: AnimationMetadata | AnimationMetadata[],
options?: AnimationQueryOptions | null
): AnimationQueryMetadata;
interface AnimationQueryOptions extends AnimationOptions {
optional?: boolean;
limit?: number;
}
interface AnimationQueryMetadata extends AnimationMetadata {
selector: string;
animation: AnimationMetadata | AnimationMetadata[];
options: AnimationQueryOptions | null;
}Usage Examples:
import { query, animate, style, stagger } from '@angular/animations';
// Animate all child elements
const animateChildren = query('.child', [
animate('300ms', style({ opacity: 0, transform: 'translateY(20px)' }))
]);
// Animate specific child elements with stagger
const staggeredChildren = query('.item', [
style({ opacity: 0, transform: 'translateX(-50px)' }),
stagger('100ms', [
animate('300ms ease-out', style({
opacity: 1,
transform: 'translateX(0)'
}))
])
]);
// Optional query (won't fail if elements not found)
const optionalQuery = query('.optional-element', [
animate('200ms', style({ opacity: 0 }))
], { optional: true });
// Limited query (animate only first 3 elements)
const limitedQuery = query('.item', [
animate('300ms', style({ backgroundColor: 'yellow' }))
], { limit: 3 });Staggers the timing of animations across multiple elements.
/**
* Staggers animation timing for multiple elements
* @param timings - Delay between each element's animation start
* @param animation - Animation to apply with staggered timing
* @returns AnimationStaggerMetadata for staggered execution
*/
function stagger(
timings: string | number,
animation: AnimationMetadata | AnimationMetadata[]
): AnimationStaggerMetadata;
interface AnimationStaggerMetadata extends AnimationMetadata {
timings: string | number;
animation: AnimationMetadata | AnimationMetadata[];
}Usage Examples:
import { stagger, animate, style, query } from '@angular/animations';
// Basic stagger effect
const basicStagger = stagger('100ms', [
animate('300ms', style({ opacity: 1, transform: 'translateY(0)' }))
]);
// Stagger with query for list items
const listStagger = query('.list-item', [
style({ opacity: 0, transform: 'translateX(-50px)' }),
stagger('150ms', [
animate('400ms cubic-bezier(0.35, 0, 0.25, 1)', style({
opacity: 1,
transform: 'translateX(0)'
}))
])
]);
// Reverse stagger (negative timing)
const reverseStagger = stagger('-100ms', [
animate('300ms', style({ opacity: 0 }))
]);import { trigger, transition, group, sequence, animate, style, query, stagger } from '@angular/animations';
trigger('complexAnimation', [
transition(':enter', [
// First, set initial styles
style({ opacity: 0 }),
// Then run parallel animations
group([
// Main element animation
sequence([
animate('200ms', style({ opacity: 1 })),
animate('300ms', style({ transform: 'scale(1.05)' })),
animate('200ms', style({ transform: 'scale(1)' }))
]),
// Child elements animation
query('.child', [
style({ opacity: 0, transform: 'translateY(20px)' }),
stagger('50ms', [
animate('300ms ease-out', style({
opacity: 1,
transform: 'translateY(0)'
}))
])
], { optional: true })
])
])
])trigger('cardGrid', [
transition(':enter', [
query('.card', [
style({
opacity: 0,
transform: 'translateY(50px) scale(0.8)'
}),
stagger('100ms', [
group([
animate('300ms cubic-bezier(0.25, 0.46, 0.45, 0.94)',
style({ opacity: 1 })
),
animate('400ms cubic-bezier(0.68, -0.55, 0.265, 1.55)',
style({ transform: 'translateY(0) scale(1)' })
)
])
])
])
]),
transition(':leave', [
query('.card', [
stagger('-50ms', [
animate('200ms ease-in', style({
opacity: 0,
transform: 'translateY(-20px) scale(0.9)'
}))
])
])
])
])trigger('modalAnimation', [
transition(':enter', [
group([
// Backdrop fade in
query('.backdrop', [
style({ opacity: 0 }),
animate('200ms', style({ opacity: 1 }))
]),
// Modal slide and scale in
query('.modal', [
style({
opacity: 0,
transform: 'translateY(-50px) scale(0.9)'
}),
sequence([
animate('150ms', style({ opacity: 1 })),
animate('250ms cubic-bezier(0.34, 1.56, 0.64, 1)',
style({ transform: 'translateY(0) scale(1)' })
)
])
])
])
]),
transition(':leave', [
group([
// Modal slide and scale out
query('.modal', [
animate('200ms ease-in', style({
opacity: 0,
transform: 'translateY(-50px) scale(0.9)'
}))
]),
// Backdrop fade out (slower)
query('.backdrop', [
animate('300ms', style({ opacity: 0 }))
])
])
])
])// Element selectors
query('div', animation)
query('.class-name', animation)
query('#element-id', animation)
// Attribute selectors
query('[data-animate]', animation)
query('[type="button"]', animation)
// Pseudo-selectors
query(':first-child', animation)
query(':last-child', animation)
query(':nth-child(odd)', animation)
// Combinators
query('.parent > .child', animation)
query('.parent .descendant', animation)
query('.sibling + .next', animation)// All direct children
query(':enter', animation) // Entering elements
query(':leave', animation) // Leaving elements
// Self reference
query(':self', animation) // The element itself
// Animation state selectors
query('@triggerName', animation) // Elements with specific trigger
query('@*', animation) // Elements with any trigger
query('@triggerName.start', animation) // Elements starting animation
query('@triggerName.done', animation) // Elements finishing animation// Optional queries (won't throw if no elements found)
query('.might-not-exist', animation, { optional: true })
// Limited queries (animate only first N elements)
query('.item', animation, { limit: 5 })
// Combined options
query('.optional-item', animation, {
optional: true,
limit: 3,
params: { duration: '500ms' }
})// Efficient: Group transforms together
group([
animate('300ms', style({ transform: 'translateX(100px) scale(1.2)' })),
animate('300ms', style({ opacity: 0.5 }))
])
// Less efficient: Separate transform animations
group([
animate('300ms', style({ transform: 'translateX(100px)' })),
animate('300ms', style({ transform: 'scale(1.2)' })),
animate('300ms', style({ opacity: 0.5 }))
])// Good: Stagger with reasonable delays
stagger('100ms', animate('300ms', style({ opacity: 1 })))
// Consider performance: Very short staggers on many elements
stagger('10ms', animate('300ms', style({ opacity: 1 }))) // May impact performance