TrademarkTrademarkDocs
Ctrl k
Search docs...
Components

Scrubber

Updated: August 30, 2026
View on GitHub
Scrubber positions things by time rather than by layout. With no tracks it is a seek bar. Give it tracks and it is an editor timeline: stacked layers of blocks sharing one playhead, each block selectable, movable and trimmable. It is not Timeline, which lays out a sequence of steps or events down the page. Times are in whatever unit you and the component agree on — milliseconds by convention, which is what the default m:ss formatter assumes. Pass formatTime for anything else, including frames or bars. Each track is a row of blocks. movable lets the body be dragged along the track, resizable puts trim handles on the edges, and onAdd turns a click on empty track space into a new block. Blocks colour themselves from a scheme, so layers stay distinguishable. onBlockChange hands back absolute times, already clamped to [0, duration] and measured from where the gesture started — not accumulated per pointer move, so a block cannot drift away from the pointer over a long drag. Everything past that is your rule: a minimum length, no overlap with the next block, snapping to a grid. The block renders wherever you put it, so refusing a change is simply not applying it. onGestureStart fires once when a drag begins, which is the moment to snapshot for undo — one entry per gesture rather than one per pointer move. The track is a role="slider": ← and → step the playhead by step (a hundredth of the duration by default), Home and End jump to either edge. Dragging uses pointer events, so blocks and playhead work with a mouse, a pen or a finger. Block gestures stay pointer-driven. Right-clicking a block calls onBlockContextMenu with the event and the ids — build the menu yourself, since what belongs in it is entirely your application's business.
Prop
Type
Default
durationrequired
Total length of the timeline, in seconds.
number—
valuerequired
Where the playhead is, in seconds.
number—
onChangerequired
Called as the playhead is dragged or the track is clicked.
(time: number) => void—
tracks
The lanes under the playhead, each with its own blocks.
ScrubberTrack[][]
selected
Id of the currently selected block.
stringnull
null
onSelect
Called when a block is selected, or with null when it is deselected.
(blockId: string | null) => void—
onBlockChange
Called when a block is moved or resized, with its new start and end.
(trackId: string, blockId: string, next: { start: number; end: number }) => void—
onGestureStart
Called once when a drag begins — the place to pause playback.
() => void—
onBlockContextMenu
Right-click on a block, with the event and what was hit.
(event: React.MouseEvent, trackId: string, blockId: string) => void—
showTime
Show the current time next to the playhead.
booleantrue
formatTime
Turn seconds into the label shown. Defaults to m:ss.
(time: number) => stringdefaultFormatTime
step
Snap the playhead to this interval, in seconds.
number—
ariaLabel
Label for the playhead handle.
stringSeek
…and every FlexProps propinherited—
Prop
Type
Default
id
string—
blocks
ScrubberBlock[]—
height
SpacingToken40
scheme
neutralbrandaccentinfodangerwarningsuccess
—
movable
booleanfalse
resizable
booleanfalse
onAdd
(time: number) => void—
Prop
Type
Default
id
string—
start
number—
end
number—
label
ReactNode—
scheme
neutralbrandaccentinfodangerwarningsuccess
—
locked
booleanfalse
Edit this page on GitHub
TrademarkTrademark
Built with curiosity by Lorant One and the Design Engineers Club