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/themes/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/themes/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/themes/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderRangeProps
Import from @askrjs/themes/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
SliderThumbAsChildProps
Import from @askrjs/themes/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderThumbProps
Import from @askrjs/themes/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
SliderTrackAsChildProps
Import from @askrjs/themes/slider.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
ref | ref?: Ref<Element>; | — | — |
SliderTrackProps
Import from @askrjs/themes/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
Slider thumbs expose role="slider" and their current, minimum, maximum and orientation attributes. Test keyboard and pointer changes, focus ownership and listener cleanup when a drag ends or the component unmounts.
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.