23 KiB
Parts
Full API for every compound part across generic, time, and volume sliders.
Generic Slider Parts
These parts are shared across all slider types. In React, they're accessed via Slider.*. In HTML, they're <media-slider-*> elements.
Root
Container element. Owns slider state, handles pointer events (click-to-seek on track area, drag), provides context to children (CSS custom properties, data attributes, value formatting, ARIA attrs for Thumb, keyboard step values).
Not used directly — use TimeSlider.Root or VolumeSlider.Root instead. Exposed for building custom slider types.
React
import { Slider } from '@videojs/react';
<Slider.Root
value={50}
onValueChange={(value) => {}}
onValueCommit={(value) => {}}
>
{/* children */}
</Slider.Root>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
number |
— | Controlled value. |
defaultValue |
number |
0 |
Initial value (uncontrolled). |
min |
number |
0 |
Minimum value. |
max |
number |
100 |
Maximum value. |
step |
number |
1 |
Step increment for arrow keys. Also controls value snap granularity for generic slider. Domain sliders handle snap precision internally. |
largeStep |
number |
10 |
Step increment for Shift+Arrow and Page Up/Down. |
orientation |
'horizontal' | 'vertical' |
'horizontal' |
Layout direction. |
disabled |
boolean |
false |
Disables all interaction. |
thumbAlignment |
'center' | 'edge' |
'center' |
How the thumb aligns at min/max. center: thumb center at track edge (may overflow). edge: thumb stays within track bounds (uses ResizeObserver). See architecture.md. |
render |
RenderProp<SliderState> |
— | Custom render element. |
Callbacks
| Callback | Signature | Description |
|---|---|---|
onValueChange |
(value: number) => void |
Fired on every value change (pointer drag, keyboard step). Updates visual state. |
onValueCommit |
(value: number) => void |
Fired when user completes a gesture (pointer up, each keyboard step). Commits the value. |
onDragStart |
() => void |
Fired when intentional drag begins (after drag threshold). |
onDragEnd |
() => void |
Fired when drag ends. |
For keyboard input, both onValueChange and onValueCommit fire on each step — each keypress is a complete gesture.
Root has no ARIA role or attributes — those live on Thumb. See Thumb.
State
| Property | Type | Description |
|---|---|---|
value |
number |
Current value. |
fillPercent |
number |
Value as percentage (0-100). |
pointerPercent |
number |
Pointer position as percentage (0-100). |
dragging |
boolean |
User is dragging. |
pointing |
boolean |
Pointer is over the slider. |
interactive |
boolean |
Hovering, focused, or dragging. |
orientation |
'horizontal' | 'vertical' |
Layout direction. |
disabled |
boolean |
Slider is disabled. |
thumbAlignment |
'center' | 'edge' |
Thumb alignment mode. |
Data Attributes
Defined in SliderDataAttrs (slider-data-attrs.ts). Set on Root and inherited by all children (Track, Fill, Buffer, Thumb, Preview, Value).
| Attribute | Values | Description |
|---|---|---|
data-dragging |
present/absent | User is dragging. |
data-pointing |
present/absent | Pointer is over the slider. |
data-interactive |
present/absent | Hovering, focused, or dragging. |
data-orientation |
horizontal / vertical |
Layout direction. |
data-disabled |
present/absent | Slider is disabled. |
This enables element-level CSS selectors like media-slider-thumb[data-dragging] and direct Tailwind attrs like data-[dragging]:scale-120, without requiring ancestor selectors. See decisions.md.
CSS Custom Properties (output)
Defined in SliderCSSVars (slider-css-vars.ts):
| Property | Description |
|---|---|
--media-slider-fill |
Current value as percentage of range. |
--media-slider-pointer |
Pointer position as percentage of track. |
--media-slider-buffer |
Buffered range as percentage. Set by domain roots that have a buffer concept (e.g., TimeSlider). |
Events (HTML)
Generic <media-slider> dispatches custom DOM events. All events bubble.
| Event | Detail | Fires when |
|---|---|---|
value-change |
{ value: number } |
Every value change (drag, keyboard). |
value-commit |
{ value: number } |
Gesture complete (pointerup, keyboard step). |
drag-start |
— | Intentional drag begins (after threshold). |
drag-end |
— | Drag ends. |
See architecture.md — Event Interfaces for TypeScript types.
Renders
React: <div> with CSS custom properties set via style and pointer event handlers.
HTML: <media-slider> custom element. Dispatches custom DOM events for callbacks.
Track
Visual track element. Purely structural — a container for Fill and Buffer.
React
<Slider.Track>
<Slider.Fill />
</Slider.Track>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
render |
RenderProp<SliderState> |
— | Custom render element. |
Data Attributes
Inherits all data attributes from Root.
Renders
React: <div>.
HTML: <media-slider-track>.
Fill
Filled portion of the track. Represents the current value.
React
<Slider.Fill />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
render |
RenderProp<SliderState> |
— | Custom render element. |
Data Attributes
Inherits all data attributes from Root.
Styling
.slider-fill {
width: var(--media-slider-fill, 0%);
height: 100%;
background: white;
}
Renders
React: <div>.
HTML: <media-slider-fill>.
Buffer
Buffered/loaded range indicator. Sits inside Track alongside Fill. Only visually meaningful when the Root provides --media-slider-buffer (e.g., TimeSlider.Root sets it from buffered time ranges). If the Root doesn't set the var, Buffer renders at 0%.
React
<Slider.Buffer />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
render |
RenderProp<SliderState> |
— | Custom render element. |
Data Attributes
Inherits all data attributes from Root.
Styling
.slider-buffer {
width: var(--media-slider-buffer, 0%);
height: 100%;
background: rgba(255, 255, 255, 0.3);
}
Renders
React: <div>.
HTML: <media-slider-buffer>.
Thumb
Focusable slider handle. Carries role="slider", tabindex="0", all ARIA attributes, and keyboard event handling. Per the WAI-ARIA Slider Pattern and the Media Seek Slider Example, the thumb is the element that represents the slider to assistive technology.
Always present in the DOM. Users who want a "thumbless" visual slider hide it with CSS — the element remains focusable and announced by screen readers.
React
<Slider.Thumb />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
render |
RenderProp<SliderState> |
— | Custom render element. |
ARIA (automatic)
Set by SliderCore.getAttrs(). Domain cores extend via override getAttrs() with aria-label and aria-valuetext.
| Attribute | Source |
|---|---|
role |
"slider" |
tabIndex |
0 |
aria-valuemin |
From Root's min prop. |
aria-valuemax |
From Root's max prop. |
aria-valuenow |
Current value. |
aria-orientation |
From Root's orientation prop. |
aria-disabled |
Present when disabled. |
aria-label |
Set by domain root (e.g., "Seek", "Volume"). |
aria-valuetext |
Set by domain root (e.g., "2 minutes, 30 seconds of 10 minutes"). |
Keyboard
Handled via createSlider().thumbProps.onKeyDown. Step values come from Root's step and largeStep props via context.
| Key | Action |
|---|---|
ArrowRight / ArrowUp |
Increase by step |
ArrowLeft / ArrowDown |
Decrease by step |
Shift + Arrow |
Increase/decrease by largeStep |
PageUp |
Increase by largeStep |
PageDown |
Decrease by largeStep |
Home |
Set to minimum |
End |
Set to maximum |
0–9 |
Jump to 0%–90% of range |
Each keypress fires both onValueChange and onValueCommit. Keyboard input always commits immediately — no "keyboard drag" concept.
Data Attributes
Inherits all data attributes from Root.
Styling
.slider-thumb {
position: absolute;
left: var(--media-slider-fill, 0%);
transform: translateX(-50%);
width: 16px;
height: 16px;
border-radius: 50%;
background: white;
}
/* Visually hidden but still focusable and announced */
.slider-thumb-hidden {
position: absolute;
left: var(--media-slider-fill, 0%);
width: 0;
height: 0;
overflow: hidden;
opacity: 0;
pointer-events: none;
}
Renders
React: <div> with role="slider", tabIndex={0}, autocomplete="off", ARIA attributes, and onKeyDown.
HTML: <media-slider-thumb> with role="slider", tabindex="0", autocomplete="off", ARIA attributes, and keyboard handler.
Preview
Positioning container for preview content (time values, thumbnails, chapter titles). Tracks the pointer location. Typically shown only when interactive is true.
Preview is a dumb positioning container — it doesn't render thumbnails or fetch data. Thumbnail rendering is a separate standalone component (future work) that can be used inside Preview or independently elsewhere (poster area, video gallery, etc.). See decisions.md.
React
<Slider.Preview>
<Slider.Value type="pointer" />
</Slider.Preview>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
render |
RenderProp<SliderState> |
— | Custom render element. |
Children are rendered as-is.
Data Attributes
Inherits all data attributes from Root.
Styling
.slider-preview {
position: absolute;
bottom: 100%;
left: var(--media-slider-pointer, 0%);
transform: translateX(-50%);
pointer-events: none;
}
Visibility is the user's responsibility:
media-slider-preview[data-interactive] {
display: block;
}
media-slider-preview {
display: none;
}
Renders
React: <div>.
HTML: <media-slider-preview>.
Value
Displays a formatted slider value. Renders an <output> element.
The default formatter is String(). Domain roots provide a context-specific formatter — TimeSlider.Root provides time formatting (1:30), VolumeSlider.Root provides percentage formatting (75%). Users can override via the format prop.
React
<Slider.Value type="current" />
<Slider.Value type="pointer" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type |
'current' | 'pointer' |
'current' |
Which value to display. |
format |
(value: number) => string |
Context default or String |
Custom value formatter. |
render |
RenderProp<SliderValueState> |
— | Custom render element. |
Data Attributes
Inherits all data attributes from Root.
State (SliderValueState)
| Property | Type | Description |
|---|---|---|
type |
'current' | 'pointer' |
Which value is displayed. |
value |
number |
The numeric value. |
text |
string |
Formatted display text. |
Accessibility
The <output> element renders with aria-live="off" by default. This prevents screen readers from announcing every value change during drag (which would produce constant announcements during scrubbing). The Thumb element already provides aria-valuenow and aria-valuetext for assistive technology. Users can override to aria-live="polite" if needed. See decisions.md.
Renders
React: <output> with aria-live="off".
HTML: <media-slider-value> with type attribute and aria-live="off".
Domain Slider Roots
Domain sliders only customize Root. All other parts (Track, Fill, Buffer, Thumb, Preview, Value) are generic Slider.* parts re-exported under the domain namespace. The Root connects to the media store, provides context that aligns children (CSS custom properties, data attributes, value formatting), and sets domain-specific ARIA.
TimeSlider.Root
Connects to the media store via selectTime, selectBuffer, and selectPlayback. Provides time formatting context to Slider.Value children. Sets --media-slider-buffer from buffered ranges.
React
import { TimeSlider } from '@videojs/react';
<TimeSlider.Root>
<TimeSlider.Track>
<TimeSlider.Buffer />
<TimeSlider.Fill />
</TimeSlider.Track>
<TimeSlider.Thumb />
<TimeSlider.Preview>
<TimeSlider.Value type="pointer" />
</TimeSlider.Preview>
</TimeSlider.Root>
HTML
<media-time-slider>
<media-slider-track>
<media-slider-buffer></media-slider-buffer>
<media-slider-fill></media-slider-fill>
</media-slider-track>
<media-slider-thumb></media-slider-thumb>
<media-slider-preview>
<media-slider-value type="pointer"></media-slider-value>
</media-slider-preview>
</media-time-slider>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
'Seek' |
Accessible label for the slider. Sets aria-label on Thumb. |
step |
number |
1 |
Arrow key step in seconds. Drag uses raw precision (no step snapping) for smooth scrubbing. |
largeStep |
number |
10 |
Shift+Arrow / Page Up/Down step in seconds. |
seekThrottle |
number |
100 |
Trailing-edge throttle (ms) for seek requests during drag. 0 disables throttling. |
disabled |
boolean |
false |
Disables interaction. |
thumbAlignment |
'center' | 'edge' |
'center' |
How the thumb aligns at min/max. See Slider.Root thumbAlignment. |
render |
RenderProp<TimeSliderState> |
— | Custom render element. |
orientation is not exposed — time sliders are always horizontal. min and max are managed internally (min=0, max=duration).
| Callback | Signature | Description |
|---|---|---|
onDragStart |
() => void |
Fired when intentional drag begins. |
onDragEnd |
() => void |
Fired when drag ends. |
No value / onValueChange — the root manages value internally from the store.
State (extends SliderState)
| Property | Type | Description |
|---|---|---|
currentTime |
number |
Playback position in seconds. |
duration |
number |
Total duration in seconds. |
seeking |
boolean |
Media is seeking. |
bufferPercent |
number |
Buffered end as percentage. |
Data Attributes (extends Slider)
Defined in TimeSliderDataAttrs (time-slider-data-attrs.ts), extends SliderDataAttrs:
| Attribute | Values | Description |
|---|---|---|
data-seeking |
present/absent | Media is seeking. |
Inherited by all children (including data-seeking).
Context Provided to Children
- CSS vars: Sets
--media-slider-bufferfrom buffered ranges (in addition to base--media-slider-filland--media-slider-pointer). - Value formatting: Provides time formatter (
formatTime) toSlider.Valuechildren —type="current"shows formatted current time (1:30),type="pointer"shows formatted pointer time. - Data attributes: All slider data attributes +
data-seekingare propagated to children. - ARIA for Thumb: Provides domain-specific ARIA attrs to
Slider.Thumbvia context. - Keyboard step values:
stepdefaults to1(second),largeStepdefaults to10(seconds).
ARIA (on Thumb)
These attributes are provided by Root to the Thumb element via context:
| Attribute | Value |
|---|---|
aria-label |
From label prop (default "Seek"). |
aria-valuemin |
0 |
aria-valuemax |
Duration in seconds. |
aria-valuenow |
Current time in seconds. |
aria-valuetext |
"2 minutes, 30 seconds of 10 minutes" (on init/focus) or "2 minutes, 30 seconds" (during changes). See decisions.md. |
Behavior
- While idle:
value=currentTime. Fill tracks playback. - While dragging:
value= drag position. Seeks during drag, throttled byseekThrottle. Final seek on drag end. - On keyboard commit: calls
time.seek(seconds)immediately. - Controls auto-hide:
onDragStart/onDragEndcallbacks enable the controls feature to pause auto-hide during scrub.
Events (HTML)
<media-time-slider> dispatches drag events only. All events bubble.
| Event | Detail | Fires when |
|---|---|---|
drag-start |
— | Intentional drag begins. |
drag-end |
— | Drag ends. |
No value-change or value-commit events — value is managed from the store.
Renders
React: Renders Slider.Root with pre-configured props and time formatting context.
HTML: <media-time-slider> custom element.
VolumeSlider.Root
Connects to the media store via selectVolume. Provides percentage formatting context to Slider.Value children.
React
import { VolumeSlider } from '@videojs/react';
<VolumeSlider.Root>
<VolumeSlider.Track>
<VolumeSlider.Fill />
</VolumeSlider.Track>
<VolumeSlider.Thumb />
</VolumeSlider.Root>
HTML
<media-volume-slider orientation="vertical">
<media-slider-track>
<media-slider-fill></media-slider-fill>
</media-slider-track>
<media-slider-thumb></media-slider-thumb>
</media-volume-slider>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string |
'Volume' |
Accessible label for the slider. Sets aria-label on Thumb. |
orientation |
'horizontal' | 'vertical' |
'horizontal' |
Layout direction. |
step |
number |
1 |
Arrow key step as percentage (0-100). |
largeStep |
number |
10 |
Shift+Arrow / Page Up/Down step as percentage. |
disabled |
boolean |
false |
Disables interaction. |
thumbAlignment |
'center' | 'edge' |
'center' |
How the thumb aligns at min/max. See Slider.Root thumbAlignment. |
render |
RenderProp<VolumeSliderState> |
— | Custom render element. |
min and max are managed internally (min=0, max=100).
| Callback | Signature | Description |
|---|---|---|
onDragStart |
() => void |
Fired when intentional drag begins. |
onDragEnd |
() => void |
Fired when drag ends. |
No value / onValueChange — managed from store.
State (extends SliderState)
| Property | Type | Description |
|---|---|---|
volume |
number |
Volume level 0-1. |
muted |
boolean |
Whether muted. |
Context Provided to Children
- Value formatting: Provides percentage formatter to
Slider.Valuechildren — displays75%. - Data attributes: All slider data attributes are propagated to children.
- ARIA for Thumb: Provides domain-specific ARIA attrs to
Slider.Thumbvia context. - Keyboard step values:
stepdefaults to1(%),largeStepdefaults to10(%).
ARIA (on Thumb)
These attributes are provided by Root to the Thumb element via context:
| Attribute | Value |
|---|---|
aria-label |
From label prop (default "Volume"). |
aria-valuemin |
0 |
aria-valuemax |
100 |
aria-valuenow |
Volume as 0-100 (actual volume, even when muted). |
aria-valuetext |
"75 percent" or "75 percent, muted" when muted. |
Behavior
VolumeSlider.Rootcallsvolume.setVolume(value / 100)fromonValueChange— every pointermove and keyboard step triggers an immediate volume update.onValueCommitis not used; volume changes are cheap and instant, so there's no need for a separate commit step or throttling.- When muted, fill shows 0% but
aria-valuenowshows the actual volume.aria-valuetextcommunicates both:"75 percent, muted".
Events (HTML)
<media-volume-slider> dispatches drag events only. All events bubble.
| Event | Detail | Fires when |
|---|---|---|
drag-start |
— | Intentional drag begins. |
drag-end |
— | Drag ends. |
No value-change or value-commit events — value is managed from the store.
Renders
React: Renders Slider.Root with pre-configured props and percentage formatting context.
HTML: <media-volume-slider> custom element.
React Namespace Re-exports
Domain sliders re-export all generic Slider parts under their own namespace. Users only need one import:
// time-slider/index.parts.ts
export { Root } from './time-slider-root';
// Re-export all generic parts
export { Track, Fill, Buffer, Thumb, Preview, Value } from '../slider/index.parts';
Every part except Root is the same generic Slider.* component — re-exported for convenience.
TimeSlider.* |
Same as |
|---|---|
TimeSlider.Root |
(domain-specific) |
TimeSlider.Track |
Slider.Track |
TimeSlider.Fill |
Slider.Fill |
TimeSlider.Buffer |
Slider.Buffer |
TimeSlider.Thumb |
Slider.Thumb |
TimeSlider.Preview |
Slider.Preview |
TimeSlider.Value |
Slider.Value |
VolumeSlider.* |
Same as |
|---|---|
VolumeSlider.Root |
(domain-specific) |
VolumeSlider.Track |
Slider.Track |
VolumeSlider.Fill |
Slider.Fill |
VolumeSlider.Buffer |
Slider.Buffer |
VolumeSlider.Thumb |
Slider.Thumb |
VolumeSlider.Preview |
Slider.Preview |
VolumeSlider.Value |
Slider.Value |
Slider.* is still exported for users building custom slider types (e.g., speed slider, quality slider).
HTML Element Tags
Generic (shared across all slider types)
| Element | Tag |
|---|---|
| Root | <media-slider> |
| Track | <media-slider-track> |
| Fill | <media-slider-fill> |
| Buffer | <media-slider-buffer> |
| Thumb | <media-slider-thumb> |
| Preview | <media-slider-preview> |
| Value | <media-slider-value> |
Domain Roots
| Element | Tag |
|---|---|
| TimeSlider | <media-time-slider> |
| VolumeSlider | <media-volume-slider> |
Registration
Registration files live in src/define/ui/ (following the existing convention), exported as @videojs/html/ui/* via package.json exports. Registering a domain slider auto-registers basic structural parts (track, fill, buffer, thumb, value). Preview is registered separately — it's heavier and opt-in.
// @videojs/html/ui/time-slider
// Registers: media-time-slider + basic parts
// (media-slider-track, media-slider-fill, media-slider-buffer,
// media-slider-thumb, media-slider-value)
// @videojs/html/ui/volume-slider
// Registers: media-volume-slider + basic parts
// (media-slider-track, media-slider-fill, media-slider-buffer,
// media-slider-thumb, media-slider-value)
// @videojs/html/ui/slider-preview
// Registers: media-slider-preview (separate, opt-in)