Vize

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.