3.9 KiB
status, date
| status | date |
|---|---|
| implemented | 2026-02-26 |
PlaybackRateButton
Button for cycling through playback speeds. Displays the current rate and advances to the next on click.
Problem
Users want to speed up or slow down video playback. A button that cycles through preset rates is a common pattern — compact, one-click, no menu required.
Two things are needed:
- Store feature —
playbackRateisn't tracked in the store yet. No state, no selector, no action. - Button component — Three-layer implementation (Core + HTML + React) following existing button patterns.
Why a Separate Feature
The alternative is extending playbackFeature — adding playbackRate and setPlaybackRate to existing MediaPlaybackState. Conceptually cohesive since rate is a property of playback, and the native API puts it on the same HTMLMediaElement. But coupling means every playback subscriber re-renders on rate change, and the state can't independently track capability/support.
A separate feature wins out (per review):
- Self-contained capability — Rate support varies by provider (e.g., Vimeo required Pro, YouTube exposes
getAvailablePlaybackRates). A separate feature can later track availability without bloating the playback state. - Used independently in UI — The playback rate button only needs rate state, not
paused/ended/waiting. - Granular contracts — Aligns with the pattern of capability-scoped features.
Accessibility
aria-label: Default"Playback rate {rate}"(e.g.,"Playback rate 1.5"). Updates on rate change. Matches Media Chrome's format.aria-disabled: Present whendisabledprop is true.- Keyboard:
EnterandSpacecycle to next rate.
Deferred: Custom rates Prop
Custom rates are intentionally deferred (per review). Some providers only support specific playback rates (e.g., YouTube's getAvailablePlaybackRates), so exposing a consumer-facing rates prop without accounting for provider constraints could lead to broken UX. The store's playbackRates array is the right place — providers can populate it dynamically in the future.
When we're ready to expose custom rates, the following research applies:
Proposed API: <PlaybackRateButton rates={[0.5, 1, 1.5, 2]} /> in React, rates="0.5 1 1.5 2" (space-separated) in HTML. A component rates prop would override the store's playbackRates for that instance.
ReactiveElement converter: The HTML attribute needs a converter option on ReactiveElement since it only handles String, Boolean, and Number today. Aligns with Lit's converter API.
No auto-sorting: Rates are cycled in array order, not sorted numerically. Media Chrome sorts with .sort((a, b) => a - b), but we respect the consumer's order.
Alternatives explored:
- Property-only (no attribute) — Forces JS-only configuration, undermines declarative HTML story.
AttributeTokenList— Media Chrome'sDOMTokenList-like approach. More infrastructure than needed.Arraybuilt-in type withJSON.parse— Producesrates='[1, 1.5, 2]'which is awkward for HTML authors.min/max/step— Vidstack's approach for continuous ranges. Doesn't allow non-uniform spacing or arbitrary ordering.
References
- Media Chrome: Playback Rate Button — Default rates
[1, 1.2, 1.5, 1.7, 2], cycle on click HTMLMediaElement.playbackRate(MDN)- Issue #622