# Slider

A composable slider component with track, fill, thumb, preview, and value parts

## Import

```tsx
import { Slider } from '@videojs/react';
```

## Anatomy

```tsx
<Slider.Root>
  <Slider.Track>
    <Slider.Fill />
  </Slider.Track>
  <Slider.Thumb />
  <Slider.Preview>
    <Slider.Thumbnail.Root>
      <Slider.Thumbnail.Image />
    </Slider.Thumbnail.Root>
    <Slider.Value type="pointer" />
  </Slider.Preview>
</Slider.Root>
```

## Behavior

The base slider provides a generic range input. It manages value, pointer tracking, and drag interactions. The [time slider](https://videojs.org/docs/framework/react/reference/components/time-slider) and [volume slider](https://videojs.org/docs/framework/react/reference/components/volume-slider) add media-specific bindings. The time slider also provides parts for rendering chapter ranges and the chapter at the current interaction position.

`Slider.Thumbnail.Root` supplies the pointer value to the thumbnail. Render `Slider.Thumbnail.Image` inside it for the controlled image; other children can provide loading indicators or overlays.

The slider supports vertical orientation via the `orientation` prop (defaults to `"horizontal"`).

## Styling

Use [CSS custom properties](#css-custom-properties) to position fill, thumb, and preview elements:

React renders standard DOM elements. Add a `className` to style them:

```css
.slider-fill {
  width: var(--media-slider-fill);
}

.slider-thumb {
  left: var(--media-slider-fill);
}
```

Style based on [interaction state](#data-attributes):

```css
.slider[data-interactive] .slider-track {
  height: 6px;
}
.slider[data-pointing] .slider-preview {
  opacity: 1;
}
```

## Accessibility

Renders with `role="slider"` and automatic ARIA attributes (`aria-valuemin`, `aria-valuemax`, `aria-valuenow`, `aria-valuetext`). Override the label with the `label` prop. Keyboard controls:

- Arrow Left / Arrow Right: step by `step` increment
- Page Up / Page Down: step by `largeStep` increment
- Home: jump to minimum
- End: jump to maximum

## Examples

### Basic

A slider with track, fill, and thumb.

**App.tsx**

```tsx
import { Slider } from '@videojs/react';
import { useState } from 'react';

export default function BasicUsage() {
  const [value, setValue] = useState(50);

  return (
    <div className="demo">
      <Slider.Root className="media-slider" value={value} onValueChange={setValue}>
        <Slider.Track className="media-slider-track">
          <Slider.Fill className="media-slider-fill" />
        </Slider.Track>
        <Slider.Thumb className="media-slider-thumb" />
      </Slider.Root>
    </div>
  );
}
```

**App.css**

```css
.demo {
  display: flex;
  align-items: center;
  padding: 24px;
  background: #1a1a1a;
}

.media-slider {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  height: 20px;
  cursor: pointer;
}

.media-slider-track {
  position: absolute;
  right: 0;
  left: 0;
  height: 4px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 9999px;
  transition: height 150ms ease;
}

.media-slider[data-interactive] .media-slider-track {
  height: 6px;
}

.media-slider-fill {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--media-slider-fill);
  height: 100%;
  background: white;
  border-radius: 9999px;
}

.media-slider-thumb {
  position: absolute;
  left: var(--media-slider-fill);
  width: 14px;
  height: 14px;
  background: white;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transform: translateX(-50%) scale(0);
  transition: transform 150ms ease;
}

.media-slider[data-interactive] .media-slider-thumb {
  transform: translateX(-50%) scale(1);
}

.media-slider[data-dragging] .media-slider-thumb {
  transform: translateX(-50%) scale(1.1);
}
```

### With Preview

A slider with a pointer-tracking preview that displays the value at the current pointer position.

**App.tsx**

```tsx
import { Slider } from '@videojs/react';
import { useState } from 'react';

export default function WithPreview() {
  const [value, setValue] = useState(50);

  return (
    <div className="demo">
      <Slider.Root className="media-slider" value={value} onValueChange={setValue}>
        <Slider.Track className="media-slider-track">
          <Slider.Fill className="media-slider-fill" />
        </Slider.Track>
        <Slider.Thumb className="media-slider-thumb" />
        <Slider.Preview className="preview">
          <Slider.Value type="pointer" className="media-slider-value" />
        </Slider.Preview>
      </Slider.Root>
    </div>
  );
}
```

**App.css**

```css
.demo {
  display: flex;
  align-items: center;
  padding: 40px 24px;
  background: #1a1a1a;
}

.media-slider {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  height: 20px;
  cursor: pointer;
}

.media-slider-track {
  position: absolute;
  right: 0;
  left: 0;
  height: 4px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 9999px;
  transition: height 150ms ease;
}

.media-slider[data-interactive] .media-slider-track {
  height: 6px;
}

.media-slider-fill {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--media-slider-fill);
  height: 100%;
  background: white;
  border-radius: 9999px;
}

.media-slider-thumb {
  position: absolute;
  left: var(--media-slider-fill);
  width: 14px;
  height: 14px;
  background: white;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transform: translateX(-50%) scale(0);
  transition: transform 150ms ease;
}

.media-slider[data-interactive] .media-slider-thumb {
  transform: translateX(-50%) scale(1);
}

.media-slider[data-dragging] .media-slider-thumb {
  transform: translateX(-50%) scale(1.1);
}

.preview {
  position: absolute;
  bottom: 100%;
  margin-bottom: 6px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 150ms ease;
}

.media-slider[data-pointing] .preview {
  opacity: 1;
}

.media-slider-value {
  padding: 2px 6px;
  font-size: 12px;
  color: white;
  white-space: nowrap;
  background: rgba(0, 0, 0, 0.8);
  border-radius: 4px;
}
```

## API Reference

### Root

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Whether the slider is non-interactive. |
| `label` | `{ key: string; text: string } \| string \| ((state: SliderState) => Text \| string)` | `''` | Custom label for the slider. |
| `largeStep` | `number` | `10` | Large step increment (Page Up/Down keys). |
| `max` | `number` | `100` | Maximum value of the slider range. |
| `min` | `number` | `0` | Minimum value of the slider range. |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Axis of slider movement. |
| `step` | `number` | `1` | Step increment for value changes (arrow keys). |
| `thumbAlignment` | `'center' \| 'edge'` | `'center'` | How the thumb aligns at the track edges. `edge` constrains the thumb within track bounds. |
| `value` | `number` | `0` | Current slider value. |

#### State

State is accessible via the `render`, `className`, and `style` props.

| Property | Type | Description |
| --- | --- | --- |
| `value` | `number` | Current slider value in the min–max range. |
| `fillPercent` | `number` | Fill level as a percentage (0–100), derived from value. |
| `pointerPercent` | `number` | Pointer position as a percentage of the track (0–100). |
| `dragging` | `boolean` | Whether the user is actively dragging. |
| `pointing` | `boolean` | Whether the pointer is over the slider. |
| `interactive` | `boolean` | Whether dragging, pointing, or focus is active. |
| `orientation` | `'horizontal' \| 'vertical'` | Axis of slider movement. |
| `disabled` | `boolean` | Whether the slider is non-interactive. |
| `thumbAlignment` | `'center' \| 'edge'` | How the thumb aligns at the track edges. |

#### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-dragging` | — | Present when the user is actively dragging. |
| `data-pointing` | — | Present when the pointer is over the slider. |
| `data-interactive` | — | Present when dragging, pointing, or focus is active. |
| `data-orientation` | `'horizontal' \| 'vertical'` | Current axis of slider movement (`horizontal` or `vertical`). |
| `data-disabled` | — | Present when the slider is non-interactive. |

#### CSS custom properties

| Variable | Description |
| --- | --- |
| `--media-slider-fill` | Fill level percentage (0–100). |
| `--media-slider-pointer` | Pointer position percentage (0–100). |
| `--media-slider-buffer` | Buffer level percentage (0–100). |

### Buffer

Displays the buffered range on the slider track.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

### Fill

Displays the filled portion from start to the current value.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

### Preview

Positioning container for preview content that tracks the pointer along the slider.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `overflow` | `'clamp' \| 'visible'` | — | How the preview handles slider boundaries. `clamp` keeps it within bounds; `visible` lets it extend past them. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

#### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-dragging` | — | Present when the user is actively dragging. |
| `data-pointing` | — | Present when the pointer is over the slider. |
| `data-interactive` | — | Present when dragging, pointing, or focus is active. |
| `data-orientation` | `'horizontal' \| 'vertical'` | Current axis of slider movement (`horizontal` or `vertical`). |
| `data-disabled` | — | Present when the slider is non-interactive. |

### Thumb

Draggable handle for setting the slider value. Receives focus and handles keyboard interaction.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

#### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-dragging` | — | Present when the user is actively dragging. |
| `data-pointing` | — | Present when the pointer is over the slider. |
| `data-interactive` | — | Present when dragging, pointing, or focus is active. |
| `data-orientation` | `'horizontal' \| 'vertical'` | Current axis of slider movement (`horizontal` or `vertical`). |
| `data-disabled` | — | Present when the slider is non-interactive. |

### Track

Contains the slider's visual track and interactive hit zone.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

### Value

Displays a formatted text representation of the slider value. Renders an `<output>` element.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: SliderState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `format` | `((value: number) => string)` | — | Custom formatter for the displayed value. Overrides the root's `formatValue`. |
| `render` | `ReactElement \| ((props: HTMLProps, state: SliderState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: SliderState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |
| `type` | `'current' \| 'pointer'` | — | Which slider value to display: the current position or the pointer position. |

#### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-dragging` | — | Present when the user is actively dragging. |
| `data-pointing` | — | Present when the pointer is over the slider. |
| `data-interactive` | — | Present when dragging, pointing, or focus is active. |
| `data-orientation` | `'horizontal' \| 'vertical'` | Current axis of slider movement (`horizontal` or `vertical`). |
| `data-disabled` | — | Present when the slider is non-interactive. |

### Thumbnail.Root

Resolves, sizes, and clips the thumbnail at the slider pointer.

Render `Slider.Thumbnail.Image` inside it for the controlled image. Other children can provide loading indicators, overlays, or temporary presentation layers.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: ThumbnailState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `render` | `ReactElement \| ((props: HTMLProps, state: ThumbnailState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: ThumbnailState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |
| `thumbnails` | `ThumbnailImage[]` | — | Pre-parsed thumbnail images — bypasses the automatic `<track>` detection. |

### Thumbnail.Image

Displays the image selected and measured by `Thumbnail.Root`.

Renders an `img`, so native image attributes and the `render` escape hatch remain available without replacing the root that owns thumbnail state.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string \| ((state: ThumbnailState) => string \| undefined)` | — | Class name or function returning class name from state. |
| `crossOrigin` | `ThumbnailCrossOrigin` | — | CORS setting for the selected image. Leave unset to follow the media element, or pass `null` to opt out. |
| `fetchPriority` | `ThumbnailFetchPriority` | — | Image fetch priority hint. |
| `loading` | `ThumbnailLoading` | — | Image loading strategy. |
| `render` | `ReactElement \| ((props: HTMLProps, state: ThumbnailState) => ReactElement \| null)` | — | Render prop for custom element. |
| `style` | `CSSProperties \| ((state: ThumbnailState) => CSSProperties \| undefined)` | — | Style or function returning style from state. |

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
