Skip to content

Slider ​

An input where the user selects a value from within a given range.

Features ​

  • Can be controlled or uncontrolled.
  • Supports multiple thumbs.
  • Supports a minimum value between thumbs.
  • Supports touch or click on track to update value.
  • Supports Right to Left direction.
  • Full keyboard navigation.

Installation ​

Install the component from your command line.

bash
npm install radix-vue

Anatomy ​

Import all parts and piece them together.

vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
</script>

<template>
  <SliderRoot>
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
  </SliderRoot>
</template>

API Reference ​

Root ​

Contains all the parts of a slider. It will render an input for each thumb when used within a form to ensure events propagate correctly.

PropTypeDefault
defaultValue
number[]
modelValue
number[]
name
string
disabled
boolean
false
orientation
enum
"horizontal"
dir
enum
inverted
boolean
false
min
number
0
max
number
100
step
number
1
minStepsBetweenThumbs
number
0
as
string | Component
div
asChild
boolean
false
EmitType
@update:modelValue
(value: number) => void
@valueCommit
(value: number[]): void
Data AttributeValue
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Track ​

The track that contains the SliderRange.

PropTypeDefault
as
string | Component
span
asChild
boolean
false
Data AttributeValue
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Range ​

The range part. Must live inside SliderTrack.

PropTypeDefault
as
string | Component
span
asChild
boolean
false
Data AttributeValue
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Thumb ​

A draggable thumb. You can render multiple thumbs.

PropTypeDefault
as
string | Component
div
asChild
boolean
false
Data AttributeValue
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Examples ​

Vertical orientation ​

Use the orientation prop to create a vertical slider.

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
</script>

<template>
  <SliderRoot class="SliderRoot" :default-value="[50]" orientation="vertical">
    <SliderTrack class="SliderTrack">
      <SliderRange class="SliderRange" />
    </SliderTrack>
    <SliderThumb class="SliderThumb" />
  </SliderRoot>
</template>
css
/* styles.css */
.SliderRoot {
  position: relative;
  display: flex;
  align-items: center;
}
.SliderRoot[data-orientation="vertical"] {
  flex-direction: column;
  width: 20px;
  height: 100px;
}

.SliderTrack {
  position: relative;
  flex-grow: 1;
  background-color: grey;
}
.SliderTrack[data-orientation="vertical"] {
  width: 3px;
}

.SliderRange {
  position: absolute;
  background-color: black;
}
.SliderRange[data-orientation="vertical"] {
  width: 100%;
}

.SliderThumb {
  display: block;
  width: 20px;
  height: 20px;
  background-color: black;
}

Create a range ​

Add multiple thumbs and values to create a range slider.

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
</script>

<template>
  <SliderRoot :default-value="[25, 75]">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
    <SliderThumb />
  </SliderRoot>
</template>

Define step size ​

Use the step prop to increase the stepping interval.

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
</script>

<template>
  <SliderRoot :default-value="[50]" :step="10">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
  </SliderRoot>
</template>

Prevent thumb overlap ​

Use minStepsBetweenThumbs to avoid thumbs with equal values.

vue
// index.vue
<script setup>
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
</script>

<template>
  <SliderRoot
    :default-value="[25, 75]"
    :step="10"
    :min-steps-between-thumbs="1"
  >
    <SliderTrack>
      <SliderRange />
    </SliderTrack>
    <SliderThumb />
    <SliderThumb />
  </SliderRoot>
</template>

Accessibility ​

Adheres to the Slider WAI-ARIA design pattern.

Keyboard Interactions ​

KeyDescription
ArrowRight
Increments/decrements by the step value depending on orientation.
ArrowLeft
Increments/decrements by the step value depending on orientation.
ArrowUp
Increases the value by the step amount.
ArrowDown
Decreases the value by the step amount.
PageUp
Increases the value by a larger step.
PageDown
Decreases the value by a larger step.
Shift + ArrowUp
Increases the value by a larger step.
Shift + ArrowDown
Decreases the value by a larger step.
Home
Sets the value to its minimum.
End
Sets the value to its maximum.

Custom APIs ​

Create your own API by abstracting the primitive parts into your own component.

Abstract all parts ​

This example abstracts all of the Slider parts so it can be used as a self closing element.

Usage ​

vue
<script setup lang="ts">
import { Slider } from './your-slider'
</script>

<template>
  <Slider :default-value="[25]" />
</template>

Implementation ​

ts
// your-slider.ts
export { default as Slider } from 'Slider.vue'
vue
 <!-- Slider.vue -->
<script setup lang="ts">
import { SlideRoot, SliderRange, type SliderRootEmits, type SliderRootProps, SliderThumb, SliderTrack, useForwardPropsEmits } from 'radix-vue'

const props = defineProps<SliderRootProps>()
const emits = defineEmits<SliderRootEmits>()

const forward = useForwardPropsEmits(props, emits)
</script>

<template>
  <SliderRoot v-bind="forward">
    <SliderTrack>
      <SliderRange />
    </SliderTrack>

    <SliderThumb v-for="(_, i) in value" :key="i" />
  </SliderRoot>
</template>

Caveats ​

Mouse events are not fired ​

Because of a limitation we faced during implementation, the following example won't work as expected and the @mousedown and @mousedown event handlers won't be fired:

vue
<SliderRoot
  @mousedown="() => { console.log('onMouseDown')  }"
  @mouseup="() => { console.log('onMouseUp')  }"
>
  …
</SliderRoot>

We recommend using pointer events instead (eg. @pointerdown, @pointerup). Regardless of the above limitation, these events are better suited for cross-platform/device handling as they are fired for all pointer input types (mouse, touch, pen, etc.).