← Animation accessor on animation and transition events

v151 · css · attribute reference

AnimationEvent.animation

A read-only, nullable attribute holding the CSSAnimation that fired this animationstart, animationiteration, animationend, or animationcancel event — null on events a script constructed without one. This page also covers the matching AnimationEventInit.animation dictionary member.

Syntax

// CSS Animations Level 2 (Working Draft) — partial interface, normative IDL
partial interface AnimationEvent {
  readonly attribute CSSAnimation? animation;
};

partial dictionary AnimationEventInit {
  CSSAnimation? animation = null;
};

// Read it on any CSS animation event:
const anim = event.animation; // CSSAnimation | null

The base AnimationEvent interface (animationName, elapsedTime, pseudoElement, constructor) is defined in CSS Animations Level 1; Level 2 adds animation via the partial interface above. Implementation divergence: Chromium's bindings type the attribute (and the dictionary member) as the Web Animations base interface, not the CSS subclass — [RuntimeEnabled=AnimationEventAnimation] readonly attribute Animation? animation; in animation_event.idl and [RuntimeEnabled=AnimationEventAnimation] Animation? animation = null; in animation_event_init.idl. For UA-dispatched events the runtime value is still a CSSAnimation; the wider static type only matters for the constructor (see the dictionary member).

Source: CSS Animations Level 2 — The AnimationEvent Interface; #dom-animationevent-animation; Chromium animation_event.idl; Chromium animation_event_init.idl

Inputs

The attribute is read-only — it takes no inputs. The UA sets it when it dispatches the event (in Chromium, the event is constructed with the firing Animation* passed straight through, in css_animations.cc). The dictionary member is the constructor input: new AnimationEvent("animationstart", { animation }). Per WebIDL interface-type conversion, the value must be an object implementing the interface (CSSAnimation per spec, Animation in Chromium) or null; omitted or explicitly undefined, it takes the declared default null.

Source: CSS Animations Level 2 — AnimationEvent and AnimationEventInit; WebIDL — interface type conversion; Chromium css_animations.cc (event construction)

Outputs

A CSSAnimation object, or null. The spec's attribute description is exact: “The CSS Animation that fired the event.” For every UA-dispatched CSS animation event — animationstart, animationiteration, animationend, animationcancel — the value is the firing animation, never null (Chromium's dispatch path always passes the animation; the level-2 dispatch algorithm fires these events only for animations with an owning element). For script-constructed events the value is whatever the init dictionary carried, defaulting to null. Identity: the object is the same instance you would find in element.getAnimations()WPT animationevent-types.html asserts event.animation strictly equals the matching getAnimations() entry — so event.animation === previouslySeenAnimation comparisons work.

Source: CSS Animations Level 2 — animation attribute definition; CSS Animations Level 2 — Event dispatch; WPT — animationevent-types.html

Errors

Reading the attribute never throws: it always has a value (CSSAnimation or null) for the event's lifetime. The traps are semantic, not exceptional: null does not mean “no animation was involved” — it marks a script-constructed event (check event.isTrusted when the distinction matters); and on engines without the attribute the property is simply absent — feature-detect with "animation" in event (or AnimationEvent.prototype) before branching, treating absence as “unknown”. Constructor-side failure modes are documented under the dictionary member's errors.

Source: CSS Animations Level 2 — animation attribute definition; DOM Standard — Event.isTrusted; ChromeStatus API feature record (activation_risks polyfill)

Context

Receiver: any AnimationEvent — UA-dispatched to the animation's owning element (the events bubble; the dispatch algorithm targets the owning element), or script-constructed.

Exposure: [Exposed=Window] — the AnimationEvent interface (and therefore this attribute) exists in window contexts only, not workers; CSS animations are a document concept. No secure-context, permission, or user-gesture requirement beyond the interface itself.

Availability: Chrome 151 per the milestone listing (Enabled by default); runtime feature AnimationEventAnimation, status stable at trunk (no flag). No owning element → no CSS animation events are dispatched at all; the animation playback events from Web Animations still fire at the CSSAnimation object itself — those are AnimationPlaybackEvents, a different interface without an animation attribute.

Source: CSS Animations Level 2 — AnimationEvent IDL (Exposed=Window); CSS Animations Level 2 — Event dispatch (owning element); Chromium runtime_enabled_features.json5; chromestatus.com/feature/6046278267043840

Lifecycle

The reference is fixed when the event is created and never changes for the event's lifetime. Across one animation's life the events all carry the same object: animationstart → (animationiteration per iteration) → exactly one of animationend or animationcancel, per the level-2 phase-change dispatch table (seeking or reversing via the Web Animations API can legitimately produce further start/end pairs — the table accounts for every phase transition). Two state subtleties worth knowing: cancelling from inside a handler (e.g. event.animation.cancel() on animationstart) produces an animationcancel whose animation is that same object, now with playState === "idle"; and after a cancel the animation leaves getAnimations() results, yet the event keeps referencing it (Blink holds the animation as a traced member — animation_ in animation_event.cc). Same-object semantics: neither spec annotates the attribute [SameObject] or [NewObject]; Blink stores the pointer and returns the identical object on every access, and WPT's identity assertion against getAnimations() pins that observable behavior.

Source: CSS Animations Level 2 — Event dispatch; Chromium animation_event.cc; WPT — animationevent-types.html

Examples

// Pause and re-time the exact animation that fired the event.
element.addEventListener("animationstart", (event) => {
  if (event.animation === null) return; // script-constructed event
  event.animation.playbackRate = 0.5;
  event.animation.finished.then(() => element.remove());
});

// Cancel it — the matching animationcancel carries the same object.
element.addEventListener("animationstart", (event) => {
  event.animation.cancel();
});
element.addEventListener("animationcancel", (event) => {
  console.log(event.animation.playState); // "idle"
});

// Constructing one explicitly (defaults to null if omitted):
const anim = element.getAnimations()[0];
const synthetic = new AnimationEvent("animationstart", {
  animationName: anim.animationName,
  elapsedTime: 0,
  animation: anim,
});
console.log(synthetic.animation === anim); // true

// Feature-detect; the getAnimations() fallback is ambiguous when the same
// keyframes run twice on one element (csswg-drafts #9010).
const getFiring = (event) => ("animation" in event)
  ? event.animation
  : event.target.getAnimations().find(a => a.animationName === event.animationName);
Source: csswg-drafts issue #9010; ChromeStatus API feature record (activation_risks polyfill); CSS Animations Level 2 — AnimationEvent

AnimationEventInit.animation

The dictionary member mirrors the attribute for constructor use: CSSAnimation? animation = null in AnimationEventInit (Chromium: Animation? animation = null). The exact WebIDL semantics, because constructor behavior is where the traps live:

Source: CSS Animations Level 2 — AnimationEventInit.animation; WebIDL — interface type conversion; WebIDL — dictionary semantics; Chromium animation_event_init.idl

AnimationEventInit.animation — outputs

The constructed event's animation attribute reads back the very object passed in (Blink copies the initializer's pointer into the event member — animation_(initializer->animation()) in animation_event.cc), or null when omitted. No wrapping, cloning, or re-resolution happens.

Source: Chromium animation_event.cc (constructor); CSS Animations Level 2 — AnimationEventInit

AnimationEventInit.animation — errors

Two throwing paths. First, type conversion: a provided value that is not null/undefined and not an Animation object (Chromium) / CSSAnimation object (spec contract) throws a TypeError out of the constructor. Second, retrieval: reading the member off the input object is a property access — a throwing getter or a Proxy with a throwing get trap propagates that exception before any conversion runs. With ordinary values the remaining failure modes are silent semantic ones: a misspelled member name is ignored, and a valid value merely echoes back — none of it proves anything about a UA-dispatched event.

Source: WebIDL — interface type conversion; WebIDL — dictionary semantics

AnimationEventInit.animation — security and privacy

An authored event can carry any Animation object — including one attached to a different element or document subtree — so event.animation on an untrusted event is not evidence of what fired anything; the authored-vs-native distinction is event.isTrusted (false for every script-constructed event). Handlers that blindly drive event.animation (pause/cancel/finish) should be aware a same-origin script can feed them arbitrary animations through dispatchEvent — the same caveat that already applies to all scripted events. The member adds no storage, permission, or cross-origin channel.

Source: DOM Standard — Event.isTrusted; CSS Animations Level 2 — Privacy Considerations

Compatibility

AnimationEvent.animation — from BCD api/AnimationEvent.json (checked 2026-07-26)
Engine / runtimeSupportNotes
Chrome151Matches the milestone listing (Enabled by default); Chrome for Android, WebView (Android + iOS), Opera, Samsung Internet are BCD mirrors
EdgemirrorBCD mirrors Chrome's data (151)
Firefox152BCD version_added: "152" (Firefox for Android mirrors); ChromeStatus records “Shipped/Shipping”
Safari27BCD version_added: "27" (Safari on iOS mirrors); ChromeStatus records “Shipped/Shipping”
Deno / Node.jsUnknownNo BCD entries as of 2026-07-26 (window-exposed DOM event API)

The BCD entry links its canonical references directly (mdn_url to this attribute's MDN page, spec_url to the css-animations-2 definition); the sibling TransitionEvent.animation entry in api/TransitionEvent.json carries identical rows, and the transition-side WPT evidence is events-008.html. WPT: css/css-animations/animationevent-types.html asserts the attribute exists on animationstart/animationend/animationiteration and strictly equals the corresponding getAnimations() entry; the interface harness expectations (animationevent-interface) were updated in the implementing CL 7914303.Not a separately tracked web-feature on webstatus.dev (animationevent query returns zero entries, checked 2026-07-26).

Source: BCD api/AnimationEvent.json; ChromeStatus API feature record; WPT — animationevent-types.html

Security and privacy

The attribute exposes no information that was not already reachable: the same CSSAnimation objects are enumerable through element.getAnimations() and document.getAnimations(), so this is an ergonomics change, not a new disclosure surface. CSS Animations Level 2 reports no privacy concerns and no security concerns; the ChromeStatus entry's security and privacy reviews are both “Not applicable”. The one behavioral caveat is authored events: a script-constructed event can carry an arbitrary Animation (see the dictionary member), so treat event.animation on untrusted events as data, not provenance — event.isTrusted separates the two.

Source: CSS Animations Level 2 — Privacy Considerations; CSS Animations Level 2 — Security Considerations; ChromeStatus API feature record (review statuses); DOM Standard — Event.isTrusted