Player Scrubber

About this component

Player Scrubber

A media timeline for audio and video with its own play button and clock, so it plays on its own or follows a real media element: chapters drawn as separate segments with small gaps that open and swell under the pointer, a buffered range, the played fill and a thumb that appears on hover and grows while dragging. A bubble above the track shows the time and the chapter under the pointer, elapsed and remaining times can sit on either side, and click and key jumps land on a soft spring while dragging follows the pointer exactly. Arrow keys seek 5 seconds (1 with Shift), Page keys a tenth, Home and End the ends, all on a native range input for full accessibility.

Usage

The import and the props worth knowing about, in one place.

import { PlayerScrubber, formatTime } from "@/components/beste/component/player-scrubber";

// Uncontrolled, with chapters and a buffered range
<PlayerScrubber
  duration={242}
  defaultValue={71}
  buffered={150}                        // seconds loaded, or [[start, end], ...]
  chapters={[
    { start: 0, title: "Intro" },
    { start: 38, title: "Says" },
    { start: 121, title: "Hammers" },
  ]}
  showTime                              // elapsed on the left, remaining on the right
/>

// Controlled by a media element: follow playback, seek on release
<PlayerScrubber
  duration={audio.duration}
  value={currentTime}
  onValueCommit={(seconds) => console.log("seek to", seconds)}
  tone="outline"                        // "muted" (default) | "outline" | "ghost"
  size="lg"                             // "sm" | "default" | "lg"
/>

formatTime(3725); // "1:02:05"

Keyboard and gestures

Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.

Left / RightSeek back or forward 5 seconds.
Shift + ArrowSeek 1 second, for fine placement.
Page Up / Page DownA tenth of the duration.
Home / EndJump to the start or the end.
Space / KPlay or pause, with the play button shown.
DragThe playhead follows the pointer exactly and seeks once on release.

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
duration*number—Length of the media, in seconds.
valuenumber—Playhead position in seconds, controlled.
defaultValuenumber—Starting playhead position in seconds, uncontrolled.
onValueChange(seconds: number) => void—Every drag frame and every key press, with the new time in seconds.
onValueCommit(seconds: number) => void—Once per gesture: on release, or after a key press. Seek the media here.
bufferednumber | [number, number][]—Loaded media: seconds from the start, or explicit `[start, end]` ranges.
chaptersPlayerChapter[]—Chapters drawn as separate segments of the track.
showTimeboolean—Elapsed time on the left and remaining time on the right.
showChapterboolean—The current chapter's title and its place in the list, above the track.
showPlayboolean—A play and pause button before the track.
playingboolean—Whether the playhead runs, controlled. With an uncontrolled value the scrubber keeps its own clock.
defaultPlayingboolean—Whether it starts running, uncontrolled.
onPlayingChange(playing: boolean) => void—
loopboolean—Start over at the end instead of stopping.
ratenumber—Playback speed of the built-in clock, 1 is real time.
tone"muted" | "outline" | "ghost"—
size"sm" | "default" | "lg"—
disabledboolean—
namestring—Form name for the underlying range input.
aria-labelstring—Accessible name. Defaults to "Seek".
classNamestring—

More Player components

View all Player