Multi Thumb Slider
Adjust several ordered values on one shared numeric track.
Usage
Two thumb range
Use two thumbs to choose the lower and upper bounds of an interval.
Drag a handle or use the arrow keys for precise steps.
<!-- Multi Thumb Slider / Two Thumb Range -->
<script setup lang="ts">
import { ref } from 'vue'
import { MultiThumbSliderRange, MultiThumbSliderRoot, MultiThumbSliderThumb, MultiThumbSliderTrack } from '@sectile/vue/multi-thumb-slider'
const thumbs = ['minimum', 'maximum']
const values = ref(['120', '340'])
</script>
<template>
<MultiThumbSliderRoot v-model="values" :thumbs="thumbs" min="50" max="500" step="10">
<MultiThumbSliderTrack>
<MultiThumbSliderRange />
<MultiThumbSliderThumb v-for="thumb in thumbs" :key="thumb" :value="thumb" />
</MultiThumbSliderTrack>
<output>{{ values.join(' – ') }}</output>
</MultiThumbSliderRoot>
</template>Three thumb thresholds
Use three thumbs to divide one numeric range into meaningful thresholds.
Drag a handle or use the arrow keys for precise steps.
<!-- Multi Thumb Slider / Three Thumb Thresholds -->
<script setup lang="ts">
import { ref } from 'vue'
import { MultiThumbSliderRange, MultiThumbSliderRoot, MultiThumbSliderThumb, MultiThumbSliderTrack } from '@sectile/vue/multi-thumb-slider'
const thumbs = ['warning', 'review', 'block']
const values = ref(['20', '55', '85'])
</script>
<template>
<MultiThumbSliderRoot v-model="values" :thumbs="thumbs" min="0" max="100" step="5">
<MultiThumbSliderTrack>
<MultiThumbSliderRange />
<MultiThumbSliderThumb v-for="thumb in thumbs" :key="thumb" :value="thumb" />
</MultiThumbSliderTrack>
<output>{{ values.join(' – ') }}</output>
</MultiThumbSliderRoot>
</template>Crossing thumbs
Prevent or normalize thumb crossing according to the configured range policy.
Drag a handle or use the arrow keys for precise steps.
<!-- Multi Thumb Slider / Crossing Thumbs -->
<script setup lang="ts">
import { ref } from 'vue'
import { MultiThumbSliderRange, MultiThumbSliderRoot, MultiThumbSliderThumb, MultiThumbSliderTrack } from '@sectile/vue/multi-thumb-slider'
const thumbs = ['minimum', 'maximum']
const values = ref(['35', '70'])
</script>
<template>
<MultiThumbSliderRoot v-model="values" :thumbs="thumbs" min="0" max="100" step="5" :policies="{ minGap: 2 }">
<MultiThumbSliderTrack>
<MultiThumbSliderRange />
<MultiThumbSliderThumb v-for="thumb in thumbs" :key="thumb" :value="thumb" />
</MultiThumbSliderTrack>
<output>{{ values.join(' – ') }}</output>
</MultiThumbSliderRoot>
</template>Controlled range
Let the parent own every thumb value in the selected interval.
Drag a handle or use the arrow keys for precise steps.
<!-- Multi Thumb Slider / Controlled Range -->
<script setup lang="ts">
import { ref } from 'vue'
import { MultiThumbSliderRange, MultiThumbSliderRoot, MultiThumbSliderThumb, MultiThumbSliderTrack } from '@sectile/vue/multi-thumb-slider'
const thumbs = ['minimum', 'maximum']
const values = ref(['120', '340'])
</script>
<template>
<MultiThumbSliderRoot v-model="values" :thumbs="thumbs" min="50" max="500" step="10">
<MultiThumbSliderTrack>
<MultiThumbSliderRange />
<MultiThumbSliderThumb v-for="thumb in thumbs" :key="thumb" :value="thumb" />
</MultiThumbSliderTrack>
<output>{{ values.join(' – ') }}</output>
</MultiThumbSliderRoot>
</template>API
Vue package: @sectile/vue/multi-thumb-slider
MultiThumbSliderRootMultiThumbSliderTrackMultiThumbSliderRangeMultiThumbSliderThumb
Props
MultiThumbSliderRootProps
as- Type
PrimitiveAsDefault'div'Element or component rendered for this part.
asChild- Type
booleanDefaultfalseWhether to merge this part into its single child instead of rendering a wrapper.
defaultValue- Type
readonly (number | string)[]DefaultundefinedInitial value used when the component owns its state.
disabled- Type
booleanDefaultfalseWhether interaction is unavailable.
form- Type
stringDefaultundefinedID of the native form associated with the control.
formatValue- Type
(value: string, id: string) => stringDefaultundefinedFormats a value for visible text.
getThumbLabel- Type
(id: string) => stringDefaultundefinedReturns the accessible label for a slider thumb.
label- Type
stringDefaultundefinedAccessible name announced for the control.
max- Type
number | stringDefault100Largest value accepted by the component.
min- Type
number | stringDefault0Smallest value accepted by the component.
modelValue- Type
readonly (number | string)[]DefaultundefinedCurrent value when state is controlled by the parent.
name- Type
stringDefaultundefinedName used for native form submission.
orientation- Type
'horizontal' | 'vertical'Default'horizontal'Axis used for layout and keyboard movement.
policies- Type
MultiThumbSliderPoliciesDefaultundefinedBehavior policies that customize validation, movement, or selection.
readonly- Type
booleanDefaultfalseWhether the value can be inspected but not changed.
required- Type
booleanDefaultfalseWhether the control must contain a valid value before submission.
step- Type
number | stringDefault1Smallest value increment accepted by the component.
thumbs- Type
readonly string[]DefaultRequiredOrdered slider thumb definitions.
MultiThumbSliderThumbProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
value- Type
stringDefaultRequiredCurrent value exposed by this contract.
MultiThumbSliderPartProps
as- Type
PrimitiveAsDefaultVaries by partElement or component rendered for this part.
asChild- Type
booleanDefaultfalseWhether to merge this part into its single child instead of rendering a wrapper.
Slots
MultiThumbSliderRootSlotProps
activeThumb- Type
string | nullIndex of the thumb currently being adjusted.
disabled- Type
booleanWhether interaction is unavailable.
percentages- Type
readonly number[]Percentage position for each thumb.
readonly- Type
booleanWhether the value can be inspected but not changed.
values- Type
readonly string[]Current ordered value collection.
MultiThumbSliderThumbSlotProps
activeThumb- Type
string | nullIndex of the thumb currently being adjusted.
disabled- Type
booleanWhether interaction is unavailable.
index- Type
numberZero-based position in the parent collection.
percentage- Type
numberCurrent value expressed as a percentage of its range.
percentages- Type
readonly number[]Percentage position for each thumb.
readonly- Type
booleanWhether the value can be inspected but not changed.
value- Type
stringCurrent value exposed by this contract.
values- Type
readonly string[]Current ordered value collection.
Events
MultiThumbSliderRoot
update:modelValue- Payload
readonly string[]Emitted when the component requests a new controlled value.
Other types
MultiThumbSliderThumbLabelResolver
type MultiThumbSliderThumbLabelResolver = NonNullable<MultiThumbSliderRootProps['getThumbLabel']>MultiThumbSliderValueFormatter
type MultiThumbSliderValueFormatter = NonNullable<MultiThumbSliderRootProps['formatValue']>MultiThumbSliderValueChangeHandler
type MultiThumbSliderValueChangeHandler = (values: readonly string[]) => voidParts
Shared scope: [data-scope="multi-thumb-slider"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
track | [data-part="track"] | Defines the measurable path used by one or more thumbs. | — |
range | [data-part="range"] | Shows the active interval on the track. | — |
thumb | [data-part="thumb"] | Controls one value along the track. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow Right / Arrow Up | Increase the value by one step. |
| Arrow Left / Arrow Down | Decrease the value by one step. |
| Home / End | Move to the minimum or maximum value. |
| Page Up / Page Down | Change the value by the configured page step when supported. |
Accessibility
Every thumb is separately named and exposes its own minimum, maximum, current value, and orientation.
See the corresponding WAI-ARIA pattern for the host accessibility contract.
