# media-slider

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

## Import

```ts
import '@videojs/html/ui/slider';
import '@videojs/html/ui/slider-track';
import '@videojs/html/ui/slider-fill';
import '@videojs/html/ui/slider-thumb';
import '@videojs/html/ui/slider-preview';
import '@videojs/html/ui/slider-thumbnail';
import '@videojs/html/ui/slider-value';
```

## Anatomy

```html
<media-slider>
  <media-slider-track>
    <media-slider-fill></media-slider-fill>
  </media-slider-track>
  <media-slider-thumb></media-slider-thumb>
  <media-slider-preview>
    <media-slider-thumbnail>
      <img alt="" decoding="async" />
    </media-slider-thumbnail>
    <media-slider-value type="pointer"></media-slider-value>
  </media-slider-preview>
</media-slider>
```

## 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/html/reference/components/time-slider) and [volume slider](https://videojs.org/docs/framework/html/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.

`media-slider-thumbnail` supplies the pointer value and draws the image in its shadow DOM. Supply an `<img>` child to replace it: the element controls `src` and `srcset` on your image, and 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:

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

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

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

```css
media-slider[data-interactive] media-slider-track {
  height: 6px;
}
media-slider[data-pointing] media-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.

**index.html**

```html
<div class="demo">
  <media-slider class="media-slider" value="50">
    <media-slider-track class="media-slider-track">
      <media-slider-fill class="media-slider-fill"></media-slider-fill>
    </media-slider-track>
    <media-slider-thumb class="media-slider-thumb"></media-slider-thumb>
  </media-slider>
</div>
```

**index.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);
}
```

**index.ts**

```ts
import '@videojs/html/ui/slider';
import '@videojs/html/ui/slider-track';
import '@videojs/html/ui/slider-fill';
import '@videojs/html/ui/slider-thumb';
```

### With Preview

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

**index.html**

```html
<div class="demo">
  <media-slider class="media-slider" value="50">
    <media-slider-track class="media-slider-track">
      <media-slider-fill class="media-slider-fill"></media-slider-fill>
    </media-slider-track>
    <media-slider-thumb class="media-slider-thumb"></media-slider-thumb>
    <media-slider-preview class="preview">
      <media-slider-value type="pointer" class="media-slider-value"></media-slider-value>
    </media-slider-preview>
  </media-slider>
</div>
```

**index.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;
}
```

**index.ts**

```ts
import '@videojs/html/ui/slider';
import '@videojs/html/ui/slider-track';
import '@videojs/html/ui/slider-fill';
import '@videojs/html/ui/slider-thumb';
import '@videojs/html/ui/slider-preview';
import '@videojs/html/ui/slider-value';
```

## API Reference

### media-slider

#### 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` (attribute `large-step`) | `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` (attribute `thumb-alignment`) | `'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 reflected as data attributes for CSS styling.

| 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). |

#### Events

| Event | Description |
| --- | --- |
| `drag-end` | Fired when a pointer drag ends. |
| `drag-start` | Fired when a pointer drag starts. |
| `value-change` | Fired while the slider value changes during an interaction. |
| `value-commit` | Fired when an interaction commits the slider value. |

### media-slider-buffer

Displays the buffered range on the slider track.

### media-slider-fill

Displays the filled portion from start to the current value.

### media-slider-preview

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

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `overflow` | `'clamp' \| 'visible'` | — | How the preview handles slider boundaries. `clamp` keeps it within bounds; `visible` lets it extend past them. |

#### 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. |

### media-slider-thumb

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

#### 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. |

### media-slider-track

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

### media-slider-value

Writes the formatted current or pointer slider value into its own text content, replacing any children.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `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. |

### media-slider-thumbnail

`<media-thumbnail>` whose `time` follows the slider pointer. Left empty, it draws an image of its own; supply an `<img>` child to compose overlays or loading indicators beside the image it controls.

---

HTML documentation: https://videojs.org/docs/framework/html/llms.txt
All documentation: https://videojs.org/llms.txt
