Components Forms
RangeSlider
StableSelect a minimum and maximum with two thumbs that cannot cross.
Use RangeSlider to filter by a span of values, such as contract value or document age. Each thumb is its own slider with its own label, so the range is fully keyboard and screen reader accessible.
Overview
import { FormField, RangeSlider } from '@bindshq/stance-react';
export function Basic() {
const gbp = (v: number) => `£${v}k`;
return (
<div style={{ width: '100%', maxWidth: 420 }}>
<FormField label="Contract value">
<RangeSlider
defaultValue={[20, 80]}
min={0}
max={100}
step={5}
formatValue={gbp}
showValue
thumbLabels={['Minimum value', 'Maximum value']}
/>
</FormField>
</div>
);
}Light, dark and high contrast
Every Stance component is designed and tested in all three appearance modes.
Import
import { RangeSlider } from '@bindshq/stance-react';Platforms
RangeSlider has native counterparts. They share Stance tokens and intent, and use each platform’s own controls and conventions. The live previews on this page are the web implementation.
import { RangeSlider } from '@bindshq/stance-react';Examples
Minimum gap
minStepsBetween keeps the thumbs apart.
import { RangeSlider } from '@bindshq/stance-react';
export function MinimumGap() {
return (
<div style={{ width: '100%', maxWidth: 420 }}>
<RangeSlider
defaultValue={[9, 17]}
min={0}
max={24}
minStepsBetween={2}
thumbLabels={['Working hours start', 'Working hours end']}
formatValue={(v) => `${String(v).padStart(2, '0')}:00`}
showValue
marks={[
{ value: 0, label: '00:00' },
{ value: 12, label: '12:00' },
{ value: 24, label: '24:00' },
]}
/>
</div>
);
}Showing documents sent 0 to 30 days ago
import * as React from 'react';
import { RangeSlider } from '@bindshq/stance-react';
export function Controlled() {
const [range, setRange] = React.useState<[number, number]>([0, 30]);
return (
<div style={{ display: 'grid', gap: 12, width: '100%', maxWidth: 420 }}>
<RangeSlider
value={range}
onValueChange={setRange}
min={0}
max={90}
thumbLabels={['Newer than (days)', 'Older than (days)']}
/>
<span style={{ fontSize: 14 }}>
Showing documents sent {range[0]} to {range[1]} days ago
</span>
</div>
);
}API reference
| Prop | Type | Default | Description |
|---|---|---|---|
value | [number, number] | None | Controlled range. |
defaultValue | [number, number] | [min, max] | Initial range. |
onValueChange | (value: [number, number]) => void | None | Called while dragging. |
onValueCommit | (value: [number, number]) => void | None | Called when a change ends. |
minStepsBetween | number | 0 | Minimum distance between thumbs, in steps. |
thumbLabels | [string, string] | ['Minimum', 'Maximum'] | Accessible names for the thumbs. |
...props | Slider props | None | min, max, step, marks, showValue, formatValue, orientation, size, name, disabled. |
Accessibility
- Each thumb is a separate role="slider" with its own name from thumbLabels; give descriptive names like "Minimum value".
- Thumbs cannot pass each other: each thumb’s range is bounded by the other.
- With name set, values submit as name[0] and name[1].
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves between the two thumbs. |
| Arrow keys | Move the focused thumb by one step. |
| PageUp PageDown | Move by a large step. |
| Home End | Move as far as the other thumb or the bound allows. |