Player
A media playback primitive split into composable parts.
Anatomy
Player is a headless context provider. It renders no DOM of its own. A source part (PlayerAudio or PlayerVideo) registers the media element, and control parts drive it.
Every part throws if rendered outside Player, so composition mistakes surface immediately.
For embedded sources like YouTube, Vimeo, SoundCloud, Twitch, HLS, and DASH, swap PlayerAudio for PlayerVideo and pass the URL. react-player v3 wraps each provider in a custom element that implements the HTMLMediaElement interface, so the same control parts (PlayerPlayPause, PlayerSeekButton, PlayerProgress, PlayerVolume, PlayerCurrentTime, PlayerDuration) drive them transparently — no special path. PlayerWaveform is the one exception, since it needs to fetch and decode the raw audio bytes; see its section below.
API
Player
The context provider. Owns the media element reference, subscribes to native media events (timeupdate, play, pause, durationchange, volumechange), and exposes everything through usePlayer. Polls currentTime with requestAnimationFrame while playing so word-level highlights stay smooth.
PlayerAudio
Headless native <audio>. No chrome, no controls. Drop it in once per Player to register the source.
PlayerVideo
A react-player wrapper for the cases where you do want a visible player surface. Handles video files, YouTube, Vimeo, and the rest of react-player's matrix. Pass controls={false} to render a chromeless surface and drive playback through the control parts.
PlayerPlayPause
A button that toggles playback. Swaps playIcon and pauseIcon based on the state. Sets data-playing on the element when running, so a single render element can style both states.
PlayerSeekButton
A button that skips by a fixed number of seconds. Negative values seek backward. Sets data-direction to forward or back.
PlayerCurrentTime
A live text label for the current playback position. Uses formatTimestamp by default, switching between m:ss and h:mm:ss based on the duration. Pass a format callback to swap in your own formatter.
PlayerDuration
A text label for the total length of the media. Reads 0:00 until metadata loads, then updates once the duration is known. Accepts the same format callback as PlayerCurrentTime.
PlayerProgress
A thin draggable seek bar with a hover thumb. Fills the available width.
PlayerTitle
A text slot for the media's name. An unopinionated <div> styled as small foreground text. Override the className to change the size, weight, or color.
PlayerMeta
A secondary text slot for things like the source, host, or recording length. Styled as muted, smaller text so it reads as a subtitle to PlayerTitle. Same <div> escape hatch through className.
PlayerMute
A button that toggles muted on the media element. Swaps muteIcon and unmuteIcon based on state and treats volume: 0 as muted too, so a slider pulled to zero shows the muted icon. Sets data-muted for one-render styling. When the slider is at zero, clicking the button restores the last non-zero volume (or 1 if it was always silent) instead of just flipping muted, so the user always gets audible feedback from a single click.
PlayerVolume
A small horizontal slider bound to the media element's volume. Reflects external volume changes (e.g. someone hitting the system volume keys with the audio focused) through the volumechange event.
PlayerWaveform
A clickable waveform. By default it decodes the audio file once via the Web Audio API, samples it into peaks, and draws bars with the played portion in the primary color. Peaks are cached by src so multiple waveforms or remounts don't re-decode.
Direct audio sources only. The decode runs fetch(src) + decodeAudioData, which only works for URLs that return raw audio bytes with permissive CORS. YouTube, Vimeo, Twitch, and similar embeds don't expose their media files at the URL, so the fetch returns HTML and the decode silently fails. For external embeds, use PlayerProgress instead. If you have the original audio stored separately, pre-compute peaks server-side and pass them via peaks — the waveform skips the decode entirely.
The decode is async, so bars render at minHeight while the file loads and snap into shape once peaks arrive. For instant render, pre-compute peaks and pass them via peaks. A one-off Node script using audio-decode writes the JSON next to the audio file:
usePlayer
Hook for reading playback state and driving the player from any child. Must be called inside <Player>.
State:
currentTimeis the current playback position in seconds. Updated at animation-frame rate while playing.durationis the total length of the media in seconds. Stays at0until metadata loads.isPlayingistruewhile the media is playing,falsewhen paused or ended.volumeis the current volume from0to1.mutedistruewhen audio is silenced, either explicitly muted or with volume at0.
Actions:
play()starts playback.pause()pauses playback.toggle()flips between play and pause.jumpTo(seconds)seeks to an absolute time in seconds.seekBy(delta)seeks relative to the current position. Negative values rewind.setVolume(next)sets volume to a value between0and1. Unmutes automatically when raised above zero.toggleMute()flips the muted state. When called while volume is0, it restores the last audible level so a single click always produces sound.
formatTimestamp
Helper that formats a seconds value as m:ss or h:mm:ss depending on a duration hint. Exposed so custom formatters can mirror the default before adding their own tweaks.