Slider
Slider: anatomy, keyboard behavior, state, and theming in Askr.
Example
import { Field, FieldLabel, Slider } from '@askrjs/themes/components';
<Field>
<FieldLabel htmlFor="capacity">Capacity: {capacity()}</FieldLabel>
<Slider id="capacity" min={1} max={100} value={capacity()} onValueChange={setCapacity} />
</Field>Adjust a value with pointer or keyboard input.
Published props
Generated from the TypeScript declarations shipped by the installed package. Named types in the Type column define the accepted values.
SliderOwnProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
children | children?: unknown; | — | Supports literal, nested, array-mapped, and `For`-rendered descendants. |
defaultValue | defaultValue?: number | undefined; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
id | id?: string | undefined; | — | — |
max | max?: number | undefined; | — | — |
min | min?: number | undefined; | — | — |
name | name?: string | undefined; | — | — |
onValueChange | onValueChange?: ((value: number) => void) | undefined; | — | — |
orientation | orientation?: SliderOrientation | undefined; | — | — |
step | step?: number | undefined; | — | — |
value | value?: number | undefined; | — | — |
SliderProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | Supports literal, nested, array-mapped, and `For`-rendered descendants. |
defaultValue | defaultValue?: number | undefined; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
id | id?: string | undefined; | — | — |
max | max?: number | undefined; | — | — |
min | min?: number | undefined; | — | — |
name | name?: string | undefined; | — | — |
onValueChange | onValueChange?: ((value: number) => void) | undefined; | — | — |
orientation | orientation?: SliderOrientation | undefined; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
step | step?: number | undefined; | — | — |
value | value?: number | undefined; | — | — |
SliderRangeAsChildProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderRangeProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
SliderThumbAsChildProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderThumbProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
SliderTrackAsChildProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderTrackProps
Import from @askrjs/ui/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
Purpose
Drag a thumb along a track to pick a number within `min`/`max` — that's what `Slider` renders and manages, from volume controls to price filters. Pointer dragging, keyboard stepping, and value snapping are all handled internally, so you never have to write pointer-move math by hand. Multiple parts (`SliderTrack`, `SliderRange`, `SliderThumb`) share state through a compound id rather than props drilling.
Install and import
Install `@askrjs/ui` for the behavior and `@askrjs/themes` for the default track/range/thumb visuals, then import from `@askrjs/ui/slider` and `@askrjs/themes/slider`. Both subpaths are real exports, so there's no need to pull in the package roots just to use a slider.
Live examples
The examples show single-thumb sliders at different `min`, `max`, and `step` configurations, including a disabled variant. Each one is built from the same four parts — `Slider`, `SliderTrack`, `SliderRange`, `SliderThumb` — so you can trace exactly which prop changed the behavior you're looking at.
Anatomy
`Slider` is the state-owning root; inside it you compose `SliderTrack` (the full-length background), `SliderRange` (the filled portion between the minimum and the current value), and `SliderThumb` (the draggable, focusable handle). All three children are plain `div` wrappers with no required props beyond what `BoxProps` already gives you.
State model
The numeric `value` can be left uncontrolled with `defaultValue` or driven externally through `value` and `onValueChange`, alongside `min`, `max`, `step`, `orientation` (`horizontal` or `vertical`), and `disabled`. Dragging the thumb or pressing arrow keys calls the same internal setter that feeds `onValueChange`, so there's no separate internal-vs-external value to reconcile. A per-slider registry — a `WeakMap` keyed by an internal identity object, not the string `sliderId` — tracks the track and thumb DOM nodes needed for pointer math; `sliderId` itself is only used to derive the track/thumb DOM element ids, not as the registry key.
Keyboard and accessibility
The thumb carries `role="slider"` with `aria-valuenow`, `aria-valuemin`, `aria-valuemax`, and `aria-orientation` kept in sync automatically, matching the `SLIDER_A11Y_CONTRACT` export. Dragging is handled with `pointermove`/`pointerup` listeners attached only while a drag is active, and every drag ends by returning focus to the thumb so keyboard users can immediately take over with arrow keys.
Styling and tokens
Track, range, and thumb each expose `data-slot` for targeted styling, and the root forwards `data-disabled` and `data-orientation` so vertical sliders and disabled states can be styled without JavaScript branching. `@askrjs/themes/slider` ships sensible defaults for all of this; override the CSS custom properties rather than fighting the generated class names.
API
Beyond the value props, `Slider` takes `id` and `name` — set `name` if you want the current value to participate in a surrounding `<form>`. Values are snapped to the nearest valid `step` before `onValueChange` fires, and if `max` is configured at or below `min` the library quietly falls back to `min + step` rather than producing a zero-width or inverted track.
Edge cases
Dragging outside the track's bounding box still resolves to a valid value — the raw pointer position is snapped to the nearest `step` first, then the snapped result is clamped through `min`/`max` (not the other way around), so users don't lose the drag by moving the cursor too far. Because listeners are attached per active drag and torn down on `pointerup`, unmounting a `Slider` mid-drag doesn't leave stray global listeners behind.
Related pages
For a fixed, non-interactive value indicator rather than an input, use Progress instead — Slider is specifically for values the user changes. If you need a numeric input that also supports typing an exact value, pair it with Input rather than trying to make the thumb double as a text field.