Range Slider
Multi-thumb APG slider for value ranges with pointer dragging, keyboard, and form association.
|
|
| Package |
@vizejs/ui/range-slider |
| Maturity |
stable |
| Own the source |
vize lib pull range-slider |
| Requires |
context, controllable-state, slider |
| Aliases |
multi-thumb slider, dual slider, price range, range input |
| Covers |
WAI-ARIA Multi-Thumb Slider, React Aria RangeSlider, Radix/Reka Slider (multiple thumbs) |
Usage
import { RangeSlider, RangeSliderTrack, RangeSliderRange, RangeSliderThumb } from "@vizejs/ui/range-slider";
Or copy the source into your project with vize lib pull range-slider (see Source Distribution).
API
RangeSlider
Source: src/families/form/range-slider/range-slider.vue
Props
| Prop |
Type |
Default |
Description |
name |
string |
undefined |
Native form field name. Each thumb submits one hidden value under this name. |
form |
string |
undefined |
Id of a form owner outside the component tree. |
modelValue |
RangeSliderValue |
undefined |
Controlled thumb values. undefined selects uncontrolled behavior. |
defaultValue |
RangeSliderValue |
[min, max] |
Initial uncontrolled thumb values, also restored by form reset. The number of values sets the number of thumbs. |
min |
number |
0 |
Lower bound. |
max |
number |
100 |
Upper bound. Values less than or equal to min are repaired to min + 1. |
step |
number |
1 |
Positive step between selectable values. |
largeStep |
number |
step * 10 |
Positive step used by Page Up and Page Down. |
minStepsBetweenThumbs |
number |
0 |
Minimum number of steps kept between neighboring thumbs. |
orientation |
RangeSliderOrientation |
"horizontal" |
Logical orientation exposed to ARIA, keyboard, and pointer mapping. |
dir |
RangeSliderDirection |
"ltr" |
Text direction. RTL mirrors horizontal pointer mapping and arrow keys. |
disabled |
boolean |
false |
Disable interaction, focus, and native form submission. |
getValueText |
RangeSliderValueText |
undefined |
Formats aria-valuetext for each thumb. |
ariaLabel |
string |
undefined |
Accessible name of the group when no label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the group and every thumb. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe every thumb. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
RangeSliderAriaInvalid |
false |
Invalid state announced to assistive technology. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: RangeSliderValue] |
Fired whenever a thumb requests new values, including every drag frame. |
change |
[value: RangeSliderValue, thumbIndex: number, source: RangeSliderChangeSource] |
Fired once a change is committed (key press, pointer release, or API call). |
Slots
| Slot |
Slot props |
Description |
default |
RangeSliderSlotState |
Renders the track, range, and one thumb per value with normalized state. |
Exposed
| Member |
Type |
Description |
values |
RangeSliderValue |
Current normalized ascending thumb values. |
percents |
readonly number[] |
Thumb positions from 0 to 100. |
min |
number |
Normalized lower bound. |
max |
number |
Normalized upper bound. |
step |
number |
Normalized positive step. |
largeStep |
number |
Normalized positive large step. |
minDistance |
number |
Normalized minimum gap between neighboring thumbs, in value units. |
orientation |
RangeSliderOrientation |
Logical orientation. |
direction |
RangeSliderDirection |
Text direction. |
disabled |
boolean |
Whether interaction is disabled. |
invalid |
boolean |
Whether the value is announced as invalid. |
activeThumb |
number | null |
Index of the thumb being dragged, or null. |
state |
RangeSliderState |
Stable state token. |
root |
HTMLSpanElement | null |
Rendered root element. |
setThumbValue |
(index: number, value: number) => boolean |
Move one thumb (clamped between its neighbors) and report whether values changed. |
setValue |
(value: RangeSliderValue) => boolean |
Replace every thumb value (normalized and sorted) and report whether values changed. |
focusThumb |
(index: number, options?: FocusOptions) => void |
Focus one thumb. |
reset |
() => boolean |
Restore the default values and report whether they changed. |
RangeSliderTrack
Source: src/families/form/range-slider/range-slider-track.vue
Slots
| Slot |
Slot props |
Description |
default |
Record<string, never> |
Track contents, typically RangeSliderRange and the thumbs. |
RangeSliderRange
Source: src/families/form/range-slider/range-slider-range.vue
Slots
| Slot |
Slot props |
Description |
default |
Record<string, never> |
Optional range contents. |
RangeSliderThumb
Source: src/families/form/range-slider/range-slider-thumb.vue
Props
| Prop |
Type |
Default |
Description |
index (required) |
number |
required |
Zero-based index of the value this thumb controls. |
ariaLabel |
string |
undefined |
Accessible name of this thumb, for example "Minimum price". |
Slots
| Slot |
Slot props |
Description |
default |
RangeSliderThumbSlotState |
Thumb contents, for example a value tooltip, with the thumb state. |
Behavior
Normative state x input -> outcome table for range-slider.vue,
range-slider-track.vue, range-slider-range.vue, and range-slider-thumb.vue
(@vizejs/ui/range-slider), following the WAI-ARIA APG multi-thumb slider
pattern. The single-thumb native Slider stays in @vizejs/ui/slider;
RangeSlider reuses its bound/step normalization (slider-state.ts) rather than
duplicating it. Every row is proven by the named test in range-slider.test.ts
or range-slider-ssr.test.ts; compile-only assertions live in
range-slider.types.test-d.ts.
| # |
State |
Input |
Outcome |
Proven by |
| R1 |
raw values |
normalize |
values snap to the grid, sort ascending, keep minStepsBetweenThumbs * step apart, and never cross neighbors; bounds repair like Slider |
normalizes, sorts, spaces, and moves values without crossing neighbors |
| R2 |
two thumbs, named |
render |
labelled role="group"; each thumb is a focusable role="slider" whose aria-valuemin/max are its neighbor-limited range; hidden input per value |
renders a labelled group of APG slider thumbs with range hooks |
| R3 |
focused thumb |
Arrow / Page / Home / End |
arrows step, pages use largeStep (default step * 10), Home/End go to the neighbor-limited bounds; distinct results emit change(values, i, "keyboard") |
keyboard moves one thumb by step, page, and bounds and commits changes |
| R4 |
RTL / vertical |
arrow keys |
RTL mirrors Left/Right; vertical sliders increase with Up |
RTL mirrors horizontal arrows and vertical sliders use up for increase |
| R5 |
idle |
pointer down, move, up on track |
the closest thumb jumps, gains focus, drags (clamped to neighbors and track), data-state="dragging"; release emits one change(..., "pointer") |
pointer down moves the closest thumb, drags it, and commits on release |
| R6 |
RTL / vertical |
pointer |
RTL measures from the right edge; vertical measures from the bottom |
pointer mapping honors RTL and vertical tracks |
| R7 |
controlled |
keyboard |
emits the request; rendered values stay on modelValue until the parent accepts |
controlled values win until the parent accepts the request |
| R8 |
in a form |
submit / reset |
submits every value under name; form reset restores defaultValue |
submits one value per thumb and restores defaults on form reset |
| R9 |
disabled |
keyboard / pointer |
thumbs stay focusable for discovery with aria-disabled, ignore keyboard and pointer input, and hidden values are disabled |
disabled sliders stay discoverable but ignore input and submit nothing |
| R10 |
imperative |
expose |
setThumbValue, setValue (normalized, thumb count follows), focusThumb, reset, and normalized state |
exposes setThumbValue, setValue, focusThumb, reset, and normalized state |
| R11 |
part without provider |
setup |
throws the stable VIZE_UI_CONTEXT_MISSING: RangeSlider diagnostic |
thumbs and parts require a RangeSlider provider |
| R12 |
SSR / hydration |
isolated requests |
byte-identical markup with CSS custom properties and value text; hydration keeps nodes and thumbs stay interactive |
renders byte-identical multi-thumb markup and hydrates without mismatches |
Public extension contract
| Surface |
Contract |
| Parts |
root, track, range, thumb. |
| Data attributes |
data-vize-ui, root data-state / data-orientation / data-dir; thumb data-index, data-active. |
| Boolean hooks |
data-disabled, data-invalid (root), data-active (thumb) are "true" only while active. |
| CSS custom properties |
Root: --vize-range-slider-range-start, --vize-range-slider-range-end. Thumb: --vize-range-slider-thumb-percent. |
| Slots |
Root default slot receives RangeSliderSlotState; render one RangeSliderThumb per values entry. |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.