← Chrome 151 reference

v151 · css · web animations · behavior change

No Auto-Rewind for AnimationTrigger Play Methods

Limited availability

  • Chrome · 151 (behavior change; AnimationTrigger itself 146)
  • Edge · mirrors Chrome
  • Firefox · not shipped, no signal
  • Safari · not shipped, no signal

Not on the Baseline register: a webstatus.dev query for animation-trigger (2026-07-28) returns no web-feature entry. Vendor positions on the ChromeStatus API record are both “No signal” (Firefox, Safari); BCD records the API as Chromium-only, and the ChromeStatus record's own compat-risk note is that only Chromium ships AnimationTrigger.

The play, play-forwards, and play-backwards actions of an AnimationTrigger no longer auto-rewind: when the trigger fires and its animation has already run to completion, the animation is not restarted. Re-running a finished animation from the start now requires an explicit rewinding action such as replay.

Experimental — API surface may move AnimationTrigger is a Chromium-only feature with no Firefox or Safari support (see the Baseline banner). Its runtime flag AnimationTrigger is stable at trunk; on versions where it is not enabled, it sits behind chrome://flags/#enable-experimental-web-platform-features. The governing CSSWG resolution (#13643, 2026-06-03) is newer than the animation-triggers-1 Editor's Draft — the draft still shows the old finished-state semantics — and the same resolution also adds play-always and removes play-once, which Chrome 151 does not implement (Chromium's IDL still lists play-once). Do not assume cross-browser behavior; test before relying on this in production.

at a glance

The changeThe trigger actions play, play-forwards, and play-backwards invoke Web Animations' “play an animation” procedure with its auto-rewind flag effectively false: a finished animation stays finished when the trigger refires. Script-called animation.play() is unchanged — it still passes auto-rewind = true and still restarts a finished animation
Chrome statusEnabled by default in Chrome 151 — desktop, Android, WebView (the milestone listing is authoritative, verified 2026-07-28; feature record, accurate_as_of 2026-07-13)
CSSWG decisionw3c/csswg-drafts #13643 — RESOLVED 2026-06-03: “play, play-f, play-b do not auto-rewind at the end; we add play-always which does; we remove play-once since that's now play behavior”. Scope boundary: this Chrome 151 change implements only the no-auto-rewind part; play-always and the play-once removal are not part of it (Chromium's animation_trigger.idl at trunk still lists play-once and has no play-always)
Spec stateThe animation-triggers-1 editor's draft action table (fetched 2026-07-28) still shows the OLD finished-column semantics (play() on finished); the spec edit implementing the resolution has not landed. This page documents the shipping Chrome 151 behavior, which follows the resolution
Runtime flagAnimationTrigger — status stable at trunk, implied_by EventTrigger and TimelineTrigger (runtime_enabled_features.json5)
WPTanimation-trigger-play-forwards-backwards.tentative.html and animation-trigger-play.tentative.html assert the new semantics (“does not restart it once finished”, “does not restart a finished animation”)
ChromeStatus5071640598806528 — No Auto-Rewind for AnimationTrigger Play Methods
Source: chromestatus.com/feature/5071640598806528; csswg-drafts #13643; animation-triggers-1 ED, fetched 2026-07-28.

why the change

play-forwards and play-backwards exist so that “opposite” events can drive opposite visual effects — for example pointerdown swelling a button and pointerup shrinking it back. Under the old table, refiring the trigger when the animation had finished invoked play(), which (per Web Animations' auto-rewind) seeks back and restarts the animation — so a second pointerdown would replay the swell from the start instead of leaving the button swelled. The CSSWG discussion concluded developers do not expect a finished animation to restart, and resolved that the play actions do not auto-rewind; the resolution was applied to play as well “for consistency” (feature motivation).

Source: w3c/csswg-drafts issue #13643 — problem statement and 2026-06-03 resolution; ChromeStatus API record (motivation).

syntax

The actions are values of <animation-action>, used in the animation-trigger shorthand (and, in Chromium's JS API, as AnimationTriggerBehavior enum values):

/* animation-triggers-1 grammar */
animation-trigger: [ none | [ <dashed-ident> <animation-action>+ ]+ ]#
event-trigger-source: [ none | <event-trigger-event>+ [ / <event-trigger-event>+ ]? ]#

<animation-action> = none | play | play-once | play-forwards | play-backwards | pause | reset | replay
// Chromium IDL — animation_trigger.idl (trunk)
// https://drafts.csswg.org/web-animations-2/#the-animationtrigger-interface
// https://github.com/w3c/csswg-drafts/issues/12611#issue-3326243729
enum AnimationTriggerBehavior {
  "play",
  "pause",
  "reset",
  "play-once",
  "play-forwards",
  "play-backwards",
  "replay",
  "none",
};

[
    Exposed=Window,
    RuntimeEnabled=AnimationTrigger
] interface AnimationTrigger {
  [RaisesException] void addAnimation(Animation animation,
                                      AnimationTriggerBehavior activateBehavior,
                                      optional AnimationTriggerBehavior deactivateBehavior = "none");
  void removeAnimation(Animation animation);
  sequence<Animation> getAnimations();
};

Concrete trigger subclasses (timeline_trigger.idl, event_trigger.idl): TimelineTrigger is constructed with a sequence of options and exposes a ranges list; EventTrigger takes EventTriggerOptions and exposes eventType/eventTarget.

Source: animation-triggers-1 — animation-trigger property (grammar verbatim); Chromium animation_trigger.idl (IDL verbatim).

before and after

The animation-triggers-1 editor's draft (fetched 2026-07-28) still publishes the OLD table. The “after” column is the CSSWG resolution as implemented in Chrome 151 and asserted by WPT:

KeywordExtra effectTrigger fires, animation is finished — BEFORE (current draft)AFTER (Chrome 151 / CSSWG resolution)
playplay() — restarts the finished animation (auto-rewind)no effect — the animation stays finished
play-forwardsset playback rate to positiveplay() — restartsno restart — but see the direction nuance below
play-backwardsset playback rate to negativeplay() — restartsno restart — mirror of play-forwards
replayset progress to 0play()unchanged — this is the explicit-rewind action
pause / reset / play-once / noneunchanged by this feature (play-once already did nothing when finished; note the CSSWG separately resolved to remove play-once and add play-always — not part of Chrome 151)

The direction nuance (from WPT, not prose): play-forwards sets the playback rate positive before the state-specific step. If the animation finished playing backwards (playback rate −1, current time 0), a play-forwards trigger flips the rate to +1 and the animation plays forwards from time 0 — that is a direction reversal, not an auto-rewind, and it still happens. What no longer happens is replaying an animation that finished in the same direction: rate already +1, current time at the end → refiring does nothing. play-backwards mirrors this exactly.

Source: animation-triggers-1 ED action table (before); csswg-drafts #13643 resolution (after); WPT play-forwards-backwards test — “plays a finished animation if reversing direction, and does not restart it once finished”.
Spec-vs-implementation divergence (read before citing) Three layers are currently out of sync, and this page labels each claim with its layer:

action: play

Plays the associated animation when the trigger activates. After Chrome 151, a finished animation is left finished; a paused animation resumes from its current time (WPT: “play behavior resumes a paused animation”, “play behavior does not restart a finished animation”).

Syntax
<animation-action> = play — used as animation-trigger: --name play, or trigger.addAnimation(anim, "play") (animation-triggers-1 <animation-action>).
Inputs
No parameters. The action applies to the animation(s) associated with the trigger name (CSS) or passed to addAnimation (JS); the number of actions a trigger accepts depends on its type (event triggers one, optionally a second for stateful; timeline triggers one, optionally a second — animation-triggers-1).
Outputs
Observable play states per WPT: idle/initial → running; paused → resumes (current time continues from where it paused); playing → no effect; finished → stays finished (no restart) — WPT animation-trigger-play.tentative.html.
Errors
As a CSS value, an unknown keyword makes the declaration invalid at computed-value time (standard CSS error handling). No exception path exists for the CSS form. For the JS enum form, see the AnimationTriggerBehavior section.
Context
Applies to animations associated with a trigger via animation-trigger (CSS) or AnimationTrigger.addAnimation (JS, Window-exposed, RuntimeEnabled=AnimationTrigger, stable at trunk — runtime_enabled_features.json5). No permission or secure-context requirement is recorded in the sources consulted.
Lifecycle
Fires on trigger activation (stateless: every activation; stateful: only on the inactive→active transition). If the same trigger name is specified multiple times, all but the last have no effect; simultaneous triggers take effect in specified order (animation-triggers-1). The no-rewind state test is the animation's play state at invocation time: finished (same-direction) → nothing happens.
Examples
.target {
  animation: expand linear 10s both;
  /* play once when --t activates; if it already finished, stay finished */
  animation-trigger: --t play;
}
/* Explicit rewind instead: animation-trigger: --t replay; */
Compatibility
Behavior change: Chrome 151+ (desktop, Android, WebView — ChromeStatus record; no BCD entry yet — interim). The underlying action exists since Chrome 146 (BCD). Firefox/Safari: no AnimationTrigger support and no signal.
SurfaceChromeFirefoxSafari
play action (no-rewind semantics)151+n/a — API unsupportedn/a — API unsupported
play action (original semantics)146–150n/an/a

Behavior-change row is interim from the ChromeStatus record (no BCD entry yet); the keyword itself dates to Chrome 146 per BCD. Firefox/Safari: no AnimationTrigger support and no signal.

Security / privacy
animation-triggers-1 records no known privacy or security impacts for the triggers feature (§3, §4); this behavior change alters no trust boundary.

action: play-forwards

Sets the animation's playback rate to positive, then plays. The motivating use case is paired opposite effects (e.g. pointerdown/pointerup). After Chrome 151 it does not restart an animation that already finished in the forwards direction — but it still reverses an animation that finished playing backwards.

Syntax
<animation-action> = play-forwardsanimation-trigger: --press play-forwards, or trigger.addAnimation(anim, "play-forwards", "play-backwards") (animation-triggers-1 value definition).
Inputs
No parameters. The extra effect (set playback rate positive) happens regardless of the animation's current state, before the state-specific action (action table caption).
Outputs
Per WPT: finished-at-start with playback rate −1 → rate flips to +1, animation runs forwards (direction reversal, still supported); finished-at-end with rate +1 → exit + re-enter leaves it finished at the end, rate +1 (WPT play-forwards-backwards test: “plays a finished animation if reversing direction, and does not restart it once finished”).
Errors
Unknown CSS keywords invalidate the declaration; no runtime exception path. JS enum form: see AnimationTriggerBehavior.
Context
Same association paths as play. Works with both timeline triggers (e.g. timeline-trigger: --t view() 150px 200px) and event triggers (animation-triggers-1 §2).
Lifecycle
Rate is set positive first, then the finished-state test applies: if the animation's play state is finished at the positive-rate end, nothing further happens; if it finished at the opposite boundary (rate negative, time 0), the rate flip makes it runnable and it plays forwards from 0 (WPT).
Examples
@keyframes press-animation {
  to { transform: translate(-5px, 5px); }
}
button {
  animation: press-animation forwards;
  event-trigger: --press pointerdown / pointerup;   /* stateful: enter/exit */
  animation-trigger: --press play-forwards play-backwards;
}
/* Repeated pointerdowns no longer restart the swell;
   pointerup plays it back once. */
Compatibility
Behavior change: Chrome 151+ (interim — no BCD entry yet); keyword itself since Chrome 146 (BCD). Firefox/Safari: unsupported, no signal.
SurfaceChromeFirefoxSafari
play-forwards (no-rewind semantics)151+n/a — API unsupportedn/a — API unsupported
play-forwards (original semantics)146–150n/an/a

Interim data as above (ChromeStatus record, BCD).

Security / privacy
No known privacy or security impact per animation-triggers-1 §3/§4.

action: play-backwards

The exact mirror of play-forwards: sets the playback rate negative, then plays. After Chrome 151 it does not restart an animation that already finished in the backwards direction, but still reverses one that finished playing forwards.

Syntax
<animation-action> = play-backwardsanimation-trigger: --depress play-backwards, or as the deactivate behavior trigger.addAnimation(anim, "play-forwards", "play-backwards") (animation-triggers-1 value definition).
Inputs
No parameters. Extra effect: set playback rate to negative, applied before the state-specific action, regardless of state (action table caption).
Outputs
Per WPT: finished-at-end with rate +1 → rate flips to −1, animation runs backwards from the end; finished-at-start with rate −1 → exit + re-enter leaves it finished at time 0, rate −1 (WPT play-forwards-backwards test).
Errors
Unknown CSS keywords invalidate the declaration; no runtime exception path. JS enum form: see AnimationTriggerBehavior.
Context
Same association paths as play-forwards; commonly the second (deactivate/exit) action of a stateful trigger pair (animation-triggers-1 event triggers).
Lifecycle
Mirror of play-forwards: rate set negative first; finished at the negative-rate boundary (time 0) → no effect; finished at the positive boundary → plays backwards from the end (WPT).
Examples
.target {
  animation: slide 1s both;
  /* two stateless triggers: each plays one direction, never restarts */
  animation-trigger: --c1 play-forwards, --c2 play-backwards;
}
Compatibility
Behavior change: Chrome 151+ (interim — no BCD entry yet); keyword itself since Chrome 146 (BCD). Firefox/Safari: unsupported, no signal.
SurfaceChromeFirefoxSafari
play-backwards (no-rewind semantics)151+n/a — API unsupportedn/a — API unsupported
play-backwards (original semantics)146–150n/an/a

Interim data as above (ChromeStatus record, BCD).

Security / privacy
No known privacy or security impact per animation-triggers-1 §3/§4.

JS enum: AnimationTriggerBehavior play values

In Chromium's JS API, the same three actions are the "play", "play-forwards", and "play-backwards" values of AnimationTriggerBehavior, passed to AnimationTrigger.addAnimation(). The no-auto-rewind change applies identically through this path — the WPT play-forwards/backwards test drives the CSS path, while the addAnimation test exercises the same behaviors through the API.

Syntax
[RaisesException] undefined addAnimation(Animation animation, AnimationTriggerBehavior activateBehavior, optional AnimationTriggerBehavior deactivateBehavior = "none")animation_trigger.idl (verbatim in the Syntax section).
Inputs
activateBehavior: action on trigger activation (e.g. "play-forwards"); deactivateBehavior: action on deactivation, default "none" (e.g. "play-backwards"). Valid values: play, pause, reset, play-once, play-forwards, play-backwards, replay, none (IDL).
Outputs
Returns undefined; the association is observable via trigger.getAnimations() and the animation's subsequent play state. WPT: an animation added to an already-tripped (default) trigger with "play-forwards" plays to finish immediately; getAnimations() then contains it (WPT addAnimation test).
Errors
Per standard WebIDL enum conversion, a string outside the eight enumerated values throws a TypeError (WebIDL § enumeration conversion). The IDL marks addAnimation [RaisesException] but the sources consulted (IDL file, WPT, linked specs) do not enumerate further exception conditions — none are documented here rather than invented.
Context
Exposed=Window, RuntimeEnabled=AnimationTrigger (stable at trunk, implied by the EventTrigger/TimelineTrigger flags — runtime_enabled_features.json5). Note the divergence: web-animations-2's ED shows a different (older) interface shape; Chromium implements the #12611 model.
Lifecycle
Association persists until removeAnimation(animation). Activation runs the activate behavior; deactivation (for stateful/timeline triggers) runs the deactivate behavior. The no-rewind test applies at each invocation exactly as on the CSS path.
Examples
const trigger = new TimelineTrigger([{
  source: new ViewTimeline({ subject }),
  /* activation/active ranges per TimelineTriggerOptions */
}]);
trigger.addAnimation(animation, "play-forwards", "play-backwards");
// Refiring after finish: stays finished (Chrome 151+).
// trigger.addAnimation(animation, "replay"); // explicit rewind instead
Compatibility
API root: Chrome 146+ per BCD api/AnimationTrigger.json (root entry only — BCD has no member sub-entries and MDN has no AnimationTrigger page, both checked 2026-07-28); behavior change Chrome 151+ (interim, no BCD entry). Firefox/Safari: unsupported, no signal.
SurfaceChromeEdgeFirefoxSafari
AnimationTrigger / AnimationTriggerBehavior (API root)146+146 (mirror)not supportednot supported
Play values with no-rewind semantics151+151 (mirror)n/a — API unsupportedn/a — API unsupported

API row from BCD api/AnimationTrigger.json (root-only entry); behavior-change row interim from the ChromeStatus record.

Security / privacy
No known privacy or security impact per animation-triggers-1 §3/§4; the API exposes no new capability beyond animation playback control.

getting the old behavior back: replay

replay is the explicit-rewind action: its extra effect sets progress to 0, then plays — in every state including finished. Authors who relied on a play action restarting a finished animation migrate by renaming the action to replay.

Syntax
<animation-action> = replayanimation-trigger: --t replay, or trigger.addAnimation(anim, "replay") (animation-triggers-1 value definition).
Inputs
No parameters. Extra effect: set progress to 0, applied regardless of state before playing (action table caption).
Outputs
The associated animation restarts from the beginning on every activation, including from finished — the pre-151 behavior of the play* actions (animation-triggers-1 action table; WPT replay test).
Errors
Unknown CSS keywords invalidate the declaration; JS enum form follows the same WebIDL TypeError contract.
Context
Same association paths and exposure as the play actions; available since Chrome 146 (BCD). The CSSWG resolution also promises a future play-always keyword for restarting plays — not implemented in Chrome 151 (#13643 resolution).
Lifecycle
Progress is zeroed on every activation before the play step, so the animation always runs from the start; on deactivation of a stateful trigger the paired action runs instead.
Examples
/* Before 151 this restarted on every activation:
   animation-trigger: --t play;                                    */
/* After 151, use replay to keep restart-on-activation: */
.target {
  animation: expand linear 10s both;
  animation-trigger: --t replay;
}
Compatibility
Unchanged by this feature — Chrome 146+ (BCD). Firefox/Safari: unsupported, no signal.
SurfaceChromeFirefoxSafari
replay action146+ (unchanged by this feature)n/a — API unsupportedn/a — API unsupported

Per BCD; Firefox/Safari have no AnimationTrigger support and no signal.

Security / privacy
No known privacy or security impact per animation-triggers-1 §3/§4.

examples

Live example from the Chrome Platform Showcase — the play-vs-replay contrast (HEAD-checked 200, 2026-07-28). Source: chrome-platform-showcase — play-vs-replay

More interactive demos for this feature: scroll-reentry-lab and trigger-playground (both HEAD-checked 200, 2026-07-28).

browser compatibility

SurfaceChromeEdgeFirefoxSafari
AnimationTrigger API (root)146146 (mirror)not supportednot supported
animation-trigger CSS property146146 (mirror)not supportednot supported
No-auto-rewind for play actions (this feature)151 (desktop, Android, WebView)151 (mirror)n/a — API unsupportedn/a — API unsupported

The first two rows are from BCD (api/AnimationTrigger.json, css/properties/animation-trigger.json — both root-only entries, no member sub-entries). The behavior-change row has no BCD entry yet and is labelled interim from the ChromeStatus record and WPT assertions. Vendor positions on the record: Firefox and Safari both “No signal”; the record's compat-risk note states only Chromium ships AnimationTrigger.

Source: BCD api/AnimationTrigger.json; BCD css/properties/animation-trigger.json; ChromeStatus API record.

specifications

SpecificationRelevance
CSS Animation Triggers Module Level 1 (editor's draft)animation-trigger property and the <animation-action> table. ED table predates the resolution (see divergence note)
Web Animations Level 2 (editor's draft) — Animation TriggersTrigger model; its IDL sections show the older interface shape Chromium has moved past (#12611)
Web Animations — “play an animation” procedureDefines the auto-rewind flag this change bypasses; script play() passes true, unchanged

see also