Askr documentation
UI & Components

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>
Try Slider

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.

PropTypeDefaultDescription
childrenchildren?: unknown;—Supports literal, nested, array-mapped, and `For`-rendered descendants.
defaultValuedefaultValue?: number | undefined;——
disableddisabled?: boolean | undefined;——
idid?: string | undefined;——
maxmax?: number | undefined;——
minmin?: number | undefined;——
namename?: string | undefined;——
onValueChangeonValueChange?: ((value: number) => void) | undefined;——
orientationorientation?: SliderOrientation | undefined;——
stepstep?: number | undefined;——
valuevalue?: number | undefined;——

SliderProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;—Supports literal, nested, array-mapped, and `For`-rendered descendants.
defaultValuedefaultValue?: number | undefined;——
disableddisabled?: boolean | undefined;——
idid?: string | undefined;——
maxmax?: number | undefined;——
minmin?: number | undefined;——
namename?: string | undefined;——
onValueChangeonValueChange?: ((value: number) => void) | undefined;——
orientationorientation?: SliderOrientation | undefined;——
refref?: Ref<HTMLDivElement>;——
stepstep?: number | undefined;——
valuevalue?: number | undefined;——

SliderRangeAsChildProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild: true;——
childrenchildren: JSXElement;——
refref?: Ref<Element>;——

SliderRangeProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;——
refref?: Ref<HTMLDivElement>;——

SliderThumbAsChildProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild: true;——
childrenchildren: JSXElement;——
refref?: Ref<Element>;——

SliderThumbProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;——
refref?: Ref<HTMLDivElement>;——

SliderTrackAsChildProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild: true;——
childrenchildren: JSXElement;——
refref?: Ref<Element>;——

SliderTrackProps

Import from @askrjs/themes/slider.

PropTypeDefaultDescription
asChildasChild?: false | undefined;——
childrenchildren?: unknown;——
refref?: 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.

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.