.player { aspect-ratio: 16 / 9; overflow: hidden; border-radius: 12px; background: black;}.player-video { width: 100%; height: 100%;}/* The overlay is a plain <button>: make it invisible */.player-overlay { background: transparent; border: 0; padding: 0; cursor: pointer;}.player-play { position: absolute; left: 16px; bottom: 16px;}.player[data-fullscreen] { border-radius: 0;}
Give Player.Container a tabIndex (the example uses 0) so it can take focus. The keyboard shortcuts only run while focus is on the container or something inside it.
Parts accept the attributes of the element they render, plus a ref, except where noted. Every part that renders an element also sets the media state attributes.
Player.Root
renders no element
Holds the player state and shares it with the parts inside it and with the usePlayer and usePlayerControls hooks. Every other component must be rendered inside a Player.Root.
Prop
Type
Default
Description
children
ReactNode
required
The parts of the player.
lang
string
—
Locale used (via Intl) to format the seekbar’s aria-valuetext. Other labels, including the skip button’s, are always in English.
onError
(error: PlayerError) => void
—
Called when something fails, with { type: "media" | "fullscreen" | "play" | "pip", error }. For "media", error is the element’s MediaError. The handler is read once, when Player.Root mounts. Later changes are ignored.
Player.Root renders no element, so it takes no HTML attributes and no ref.
Player.Container
renders <div>
Wraps the media and its controls inside Player.Root. It is the element that enters fullscreen, and it handles the keyboard shortcuts below. It is always position: relative.
Prop
Type
Default
Description
skipInterval
number
5
Seconds to skip with ← and →. At least 1. Fractions are rounded down, and anything else throws a ReactMediaKitError.
volumeInterval
number
0.05
Volume change per ↑ or ↓ press. Above 0 and up to 1. Anything else throws a ReactMediaKitError.
Data attribute
Description
data-fullscreen
The player is fullscreen.
data-pip
The video is playing picture-in-picture.
Your onKeyDown runs before the built-in one; call event.preventDefault() in it to skip the built-in behavior.
Player.Overlay
renders <button>
A full-size button over the media (position: absolute; inset: 0; touch-action: manipulation). It has no visual styling of its own, so make it invisible with CSS, as in the example. It must be inside Player.Container; anywhere else, clicks on it are ignored.
Enter and Space play or pause immediately. A single click or tap does too, after waiting doubleClickInterval milliseconds to see whether a second click follows. A double click or tap toggles fullscreen, or calls your handler, and doesn’t play or pause.
Prop
Type
Default
Description
label
string
required
Becomes the button’s aria-label.
onDoubleClick
"fullscreen" | PointerEventHandler
"fullscreen"
What a mouse double click does: toggle fullscreen, or call your handler instead.
onDoubleTouch
"fullscreen" | PointerEventHandler
"fullscreen"
What a touch or pen double tap does: toggle fullscreen, or call your handler instead.
doubleClickInterval
number
300
Longest gap, in milliseconds, between two clicks that still counts as a double click. A single click also waits this long before playing or pausing.
Your onKeyDown, onPointerDown and onPointerUp handlers run before the built-in ones; call event.preventDefault() in one to skip its built-in behavior.
Keyboard interactions
While Seekbar.Root or Volume.Slider has focus, the arrow keys go to that slider instead; Space, Enter, M and F still work. Modifier keys aren’t checked, and only Space and Enter are ignored in form fields, so M, F and the arrows still fire while typing in an input inside the container.
Key
Action
SpaceEnter
Play or pause. Ignored while a button, link or form field has focus, so that element’s own action runs instead.
←Left arrow→Right arrow
Skip back or forward by skipInterval seconds.
↑Up arrow↓Down arrow
Raise or lower the volume by volumeInterval. Also unmutes.
M
Mute or unmute.
F
Enter or exit fullscreen.
Media state attributes
Five of these describe loading, and exactly one of them is set at a time. The other three mark features the browser lacks. Use them to hide controls that can’t work, or to style the player while it loads.
Data attribute
Description
data-media-pending
Loading hasn’t started. This is the initial state.
data-media-loading
The media has started loading.
data-media-metadata-loaded
The duration and dimensions are known, but there isn’t enough data to play yet.
data-media-playable
The media can play. It stays set if playback later stalls to buffer.
data-media-error
The media element reported an error, such as a network or decoding failure. A blocked play() call doesn’t set it; use onError for that.
data-fullscreen-unsupported
The browser can’t go fullscreen, or support hasn’t been detected yet.
data-pip-unsupported
Picture-in-picture isn’t available, such as for audio, or support hasn’t been detected yet.
data-volume-change-unsupported
The browser doesn’t let scripts set the volume, such as on iOS, or support hasn’t been detected yet.