Chapters
Playdeck exposes the chapters a provider publishes — PlayerState.chapters —
and seeks to one through the existing seekTo command. Not every provider
can report chapters: capabilities.chapters says so per source, and
Player.ChaptersMenu renders nothing until it resolves available, or while
the published list is empty.
The state
One field: chapters, a readonly Chapter[] — each entry
{ id, title, startTime, endTime }. The collection is ordered ascending by
startTime; endTime is null only for the last chapter when the media
duration is not yet known (a live stream, or a source without duration
metadata). There is no index field — position in the array already
carries it.
Player.ChaptersMenu derives the current chapter from
PlayerState.currentTime rather than reading it off any field: the last
chapter whose own startTime has been reached. It marks that rung and
updates it live as playback crosses each boundary.
Which providers publish chapters
@playdeck/provider-native parses a <track kind="chapters"> on the
<video> element into the published collection, deriving each chapter's
endTime from the next chapter's startTime (and the media duration for
the last one) — see the Capabilities matrix guide for the full account.
Seeking to a chapter
Two ways, both driving the same command: controller.seekToWithOrigin(time, 'user') directly, or Player.ChaptersMenu, which wires the whole list up
for you.
Player.ChaptersMenu
A preset assembly over Player.SettingsMenu / Player.MenuRadioGroup /
Player.MenuRadioItem, in the same shape Player.QualityMenu and
Player.PlaybackRateMenu take over the same primitives: it renders nothing
until capabilities.chapters resolves available, or while chapters is
empty; otherwise it lists one rung per chapter, reading {title} · {start time}, and marks the one containing the current playback position.
It renders no data-playdeck-part of its own — every attribute a reader can
style or query comes from the primitives it composes
(settings-menu-trigger, settings-menu, menu-radio-group,
menu-radio-item), the same Contract the other menu parts publish
through.
Pass children to fully customize the trigger/content; omit them for the default chapter list.
Accessibility
The trigger carries aria-label="Chapters", overridable the same way any
other primitive's default label is — pass your own aria-label (or replace
the trigger's children entirely). Each rung is role="menuitemradio" with
aria-checked reflecting the current chapter. Keyboard operation — Tab to
the trigger, Enter or Space to open it, arrow keys to move roving focus among
the rungs, Enter or Space to choose one, Escape to close — comes from
SettingsMenu, the same primitive every other menu in this package composes,
rather than anything ChaptersMenu implements itself.
Out of scope
Chapter markers drawn on the seek slider itself do not exist. A standalone
chapters button, outside a menu, does not exist either — PlayerState.chapters
is exposed only through Player.ChaptersMenu and the menu primitives it is
built from.