FrameScrubber
StableThe seek slider for a video clip: time in words, frame steps and a preview while dragging.
Also known as scrubber, timeline scrubber, seek bar
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Frame-accurate, with a drawn preview
0:03 of 0:08, frame 79 of 192
const [t, setT] = useState(3.25);
<FrameScrubber
label="Seek, take 3"
duration={8}
fps={24}
value={t}
onChange={setT}
renderThumbnail={(s) => <VideoScene time={s} duration={8} />}
/>
<p>{formatMediaTime(t)} of 0:08, frame {frameAt(t, 24)} of 192</p>With fps the scrubber snaps to whole frames. Focus it, then use the arrows for 1 second and comma or period for one frame. Point or drag to see the frame preview.
When to use it
Lets people find an exact moment in a short clip, down to the frame, by pointer or keyboard.
Made of: Hit area · Track · Played part · Thumb · Preview bubble with thumbnail, time and frame
Use it for
- The seek bar inside a video player.
- Picking a single frame, such as a start frame or a thumbnail.
- Any short clip where tenths of a second matter.
Not for
- Audio, where the loudness shape helps people find a moment: use Waveform.
- Picking a start and an end: use ClipRangeSelector.
- Picking a value on a scale: use Slider.
Do and avoid
Take 3, 8 seconds
Call with Maya Okafor
Do
- Pass fps for generated clips, so people can land on an exact frame.
- Keep the played part in ink and the track neutral.
- Pause playback while the person drags (onScrubbingChange).
Avoid
- Don't colour the played part with the AI colour.
- Don't shrink the 44px hit area to match a thin design.
- Don't make comma and period work when the scrubber does not have focus. VideoPlayer adds them for the whole player, with an off switch.
On a phone
- The track is 4px but the hit area is 44px tall and fills the width.
- Tap anywhere to seek. While a finger drags, the bubble shows the time and frame above it.
- A touch that starts on it does not scroll the page.
Seen in products
- Google Flow: Shift with an arrow pauses and steps one frame.
- The W3C seek slider example says the time in words, such as "4 minutes 3 seconds", not a raw number.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| durationrequired | number | none | Length in seconds. 0 shows a disabled, empty track. |
| valuerequired | number | none | Playhead in seconds. The parent owns it. |
| onChangerequired | (seconds: number) => void | none | Called with the new time after a drag, a tap or a key. |
| labelrequired | string | none | Name of the slider, such as "Seek, take 3". |
| fps | number | none | Frames per second. Turns on frame steps and snaps to frames. |
| step | number | 1 | Seconds moved by an arrow key. Page Up and Page Down move ten steps. |
| thumbnails | string[] | none | Still images spread over the clip, shown in the preview. |
| renderThumbnail | (seconds: number) => ReactNode | none | Draws the preview for a time when there are no image thumbnails. |
| onScrubbingChange | (scrubbing: boolean) => void | none | Called when a drag starts and ends, so a player can pause. |
| disabled | boolean | false | Blocks seeking. It stays focusable and says it is unavailable. |
| className | string | none | Extra classes on the wrapper. |
"Show code under the preview gives the code for the example on the stage."
In Figma
In Figma, one FrameScrubber switches all of this from its properties panel, across 5 variants. Each property sets the React prop beside it, so design and code use the same names.
| Figma property | React | Values |
|---|---|---|
| State | Hover, Pressed and Focus come from the browser. Disabled sets disabled. | Default, Hover, Pressed, Focus, Disabled |
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- dragging
- While a pointer drags, the preview bubble shows the time, frame and thumbnail.
- unknown length
- duration 0: an empty, disabled track that says "Length not known yet".
Tokens
Change one of these and every part that uses it follows.
--fg--border-strong--surface--surface-sunken--dur-fast--text-small
Built in
- It is a slider with aria-valuetext in words, such as "3.2 seconds of 8 seconds, frame 77 of 192".
- Arrow keys move by step, Page Up and Page Down by ten steps, Home and End to the ends.
- Comma and period, or Shift with an arrow, move one frame (or a tenth of a second without fps). They only work while it has focus.
- When disabled it uses aria-disabled and says "Length not known yet" when there is no length.
- The preview bubble is for sight only and hidden from screen readers; the value text carries the same facts.
- In forced colours the track and played part use system colours.
What you need to do
- Give a label that names the clip, such as "Seek, take 3".
- Update value from the real media time. Do not ease or animate it.
- Pass fps when frames matter, so the value text and keys use frames.
- Write the current time as text near it as well; the bubble only shows while dragging.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide