The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Create an animation | const animation = element.animate(keyframes, { duration: 300, easing: 'ease-out' }) | View examples |
| Use property-indexed keyframes | element.animate({ opacity: [0, 1], transform: ['scale(.95)', 'scale(1)'] }, 200) | View examples |
| Set keyframe offsets | [{ opacity: 0, offset: 0 }, { opacity: 1, offset: 0.4 }, { opacity: 1, offset: 1 }] | View examples |
| Pause playback | animation.pause() | View examples |
| Reverse safely | animation.reverse() | View examples |
| Change playback rate | animation.updatePlaybackRate(0.5) | View examples |
| Seek to a time | animation.currentTime = 150 | View examples |
| Await completion | await animation.finished | View examples |
| Await pending operations | await animation.ready | View examples |
| Commit computed values | animation.commitStyles(); animation.cancel() | View examples |
| Inspect element animations | const animations = element.getAnimations({ subtree: true }) | View examples |
| Read computed timing | const timing = animation.effect.getComputedTiming() | View examples |
| Change effect timing | animation.effect.updateTiming({ duration: 500, iterations: 2 }) | View examples |
| Detect reduced motion | const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches | View examples |
The Web Animations API exposes the timing model shared by CSS animations and transitions. It can create effects, control playback, inspect running animations, and await lifecycle milestones without frame-by-frame style writes. Preserve meaningful final state outside the animation, respect reduced-motion preferences, cancel orphaned effects, and feature-test newer methods.
Step by step
Detailed examples
Create effects from valid keyframes and explicit timing
Element.animate() constructs a KeyframeEffect and Animation bound to the document timeline. Keyframes may be an array of objects or property-indexed arrays. Property names use JavaScript form such as backgroundColor; custom properties retain their -- name. Missing offsets are distributed, while easing on an individual keyframe applies from that keyframe to the next. Animate transform and opacity when they express the design, but do not claim every such animation is guaranteed compositor-only.
const animation = card.animate([
{ opacity: 0, transform: 'translateY(12px)', offset: 0 },
{ opacity: 1, transform: 'translateY(0)', offset: 1 },
], { duration: 240, easing: 'cubic-bezier(.2,.8,.2,1)', fill: 'both' }); Control playback through the animation timeline
play(), pause(), reverse(), finish(), cancel(), playbackRate, and currentTime modify timing rather than repeatedly writing styles. updatePlaybackRate() preserves current position more predictably than assigning playbackRate during running playback. currentTime can be null when unresolved. finish() can throw InvalidStateError for an infinite-duration animation or unusable playback rate. UI controls should reflect playState rather than assuming a command took effect synchronously.
async function toggle(animation) {
if (animation.playState === 'running') animation.pause();
else animation.play();
await animation.ready;
status.textContent = animation.playState;
}
function setSpeed(animation, rate) {
if (Number.isFinite(rate) && rate !== 0) animation.updatePlaybackRate(rate);
} Handle promises, cancellation, and durable end state
ready represents the current pending play or pause task. finished is replaced whenever an animation leaves the finished state and rejects with AbortError when cancel() runs, so catch expected cancellation. Fill modes can retain an effect indefinitely and keep it in the cascade. Prefer writing the semantic final class or state, then canceling. commitStyles() can preserve the current computed effect in inline styles where supported, but it changes author styles and should be used intentionally.
async function removeWithAnimation(element) {
const animation = element.animate({ opacity: [1, 0] }, { duration: 180 });
try {
await animation.finished;
element.hidden = true;
} catch (error) {
if (error.name !== 'AbortError') throw error;
} finally {
animation.cancel();
}
} Inspect both CSS-created and script-created animations
Element.getAnimations() returns animations affecting the element, and subtree true includes descendants; Document.getAnimations() covers the document. Results include CSS animations and transitions as well as WAAPI effects. KeyframeEffect.getKeyframes() returns computed keyframes, while getComputedTiming() reports resolved timing and progress. Inspection is a snapshot; animations may finish or be replaced afterward. Avoid polling large subtrees continuously.
async function waitForMotion(container) {
const animations = container.getAnimations({ subtree: true });
await Promise.allSettled(animations.map(animation => animation.finished));
}
for (const animation of document.getAnimations()) {
console.debug(animation.playState, animation.effect?.getComputedTiming().progress);
} Update timing and understand effect composition
KeyframeEffect.updateTiming() changes delay, duration, iterations, direction, fill, and easing. Composite operations determine whether an effect replaces, adds to, or accumulates with lower-priority values, but additive behavior depends on the property's animation type and implementation support. Multiple effects participate in a defined composite order. Prefer simple replace composition for portable UI and feature-test options such as composite or newer timeline types before relying on them.
const effect = animation.effect;
if (!(effect instanceof KeyframeEffect)) throw new TypeError('Expected a keyframe effect');
effect.updateTiming({ duration: 500, iterations: 2, direction: 'alternate' });
const frames = effect.getKeyframes();
console.log(frames.map(({ offset, computedOffset }) => ({ offset, computedOffset }))); Respect reduced motion and preserve interaction semantics
Motion can trigger vestibular symptoms or obscure focus and state changes. Query prefers-reduced-motion and listen for changes when the setting should affect a long-lived application. Remove nonessential translations, zooms, parallax, and looping motion; a near-zero duration is not always equivalent because timing events and flashes may remain. Never use animation as the only state signal, never steal focus at completion, and keep controls operable while an animation is canceled or skipped.
const motionPreference = matchMedia('(prefers-reduced-motion: reduce)');
function reveal(element) {
if (motionPreference.matches) {
element.hidden = false;
return null;
}
element.hidden = false;
return element.animate({ opacity: [0, 1] }, { duration: 200 });
} Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



