Headless / Numeric

Slider

Slider captures one value on a scale. The thumb tracks a pointer drag; the arrow keys step it by step. It carries the full role="slider" ARIA and no styling.

Loading playground…
Updated 3 days agoEdit on GitHubWeb & native

What it is

A single forwardRef component — not compound. It renders a role="slider" track with two absolutely-positioned children, the fill and the thumb, each styled through its own prop. Values are clamped to [min, max] and snapped to step. The track responds to both pointer drags and the keyboard.

Install

example.tsx
yarn add @usemotif/headless
example.tsx
import { Slider } from '@usemotif/headless';

API

Slider

stable
const Slider: ForwardRefExoticComponent<SliderProps & RefAttributes<HTMLDivElement>>
value / defaultValue / onValueChangenumber / number / (next: number) => void

The value, controlled or uncontrolled.

min / max / stepnumber= 0 / 100 / 1

The scale bounds and the increment. Values are clamped and snapped.

orientation"horizontal" | "vertical"= "horizontal"

Track orientation — decides which arrow keys increment and how the fill grows.

disabledboolean= false

Removes the slider from the Tab order and ignores input.

aria-label / aria-labelledbystring

Names the slider. One is required — a slider with no name is unidentifiable.

style / thumbStyle / fillStyleCSSProperties

Inline styles for the track wrapper, the thumb, and the filled portion.

Keyboard

KeyAction
Arrow Right / UpIncrease by step
Arrow Left / DownDecrease by step
PageUp / PageDownChange by ten steps
Home / EndJump to min / max

Accessibility

Slider is a role="slider" carrying aria-valuenow, aria-valuemin, and aria-valuemax, so a screen reader announces the current value against its range. It needs a name — aria-label or aria-labelledby — and it is keyboard-operable through the arrow keys, PageUp/Down, and Home/End. A disabled slider drops out of the Tab order.

Examples

A volume control:

example.tsx
<Slider
aria-label="Volume"
value={volume}
onValueChange={setVolume}
min={0}
max={100}
style={{ height: 6, background: 'var(--colors-line-base)', borderRadius: 999 }}
fillStyle={{ height: '100%', background: 'var(--colors-action-primary-bg)', borderRadius: 999 }}
thumbStyle={{ width: 16, height: 16, borderRadius: '50%', background: '#fff', transform: 'translate(-50%, -50%)', top: '50%' }}
/>