Slider 
<script setup lang="ts">
import { ref } from 'vue'
import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'radix-vue'
const sliderValue = ref([50])
</script>
<template>
  <SliderRoot
    v-model="sliderValue"
    class="relative flex items-center select-none touch-none w-[200px] h-5"
    :max="100"
    :step="1"
  >
    <SliderTrack class="bg-blackA10 relative grow rounded-full h-[3px]">
      <SliderRange class="absolute bg-white rounded-full h-full" />
    </SliderTrack>
    <SliderThumb
      class="block w-5 h-5 bg-white shadow-[0_2px_10px] shadow-blackA7 rounded-[10px] hover:bg-violet3 focus:outline-none focus:shadow-[0_0_0_5px] focus:shadow-blackA8"
      aria-label="Volume"
    />
  </SliderRoot>
</template>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.
$ npm add radix-vueAnatomy 
Import all parts and piece them together.
<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.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
| defaultValue | [0] | number[]The value of the slider when initially rendered. Use when you do not need to control the state of the slider. | 
| dir | 'ltr' | 'rtl'The reading direction of the combobox when applicable.  | |
| disabled | false | booleanWhen  | 
| inverted | false | booleanWhether the slider is visually inverted. | 
| max | 100 | numberThe maximum value for the range. | 
| min | 0 | numberThe minimum value for the range. | 
| minStepsBetweenThumbs | 0 | numberThe minimum permitted steps between multiple thumbs. | 
| modelValue | number[]The controlled value of the slider. Can be bind as  | |
| name | string | |
| orientation | 'horizontal' | 'vertical' | 'horizontal'The orientation of the slider. | 
| step | 1 | numberThe stepping interval. | 
| Emit | Payload | 
|---|---|
| update:modelValue | [payload: number[]]Event handler called when the slider value changes | 
| valueCommit | [payload: number[]]Event handler called when the value changes at the end of an interaction. Useful when you only need to capture a final value e.g. to update a backend service. | 
| Slots (default) | Payload | 
|---|---|
| modelValue | number[]Current slider values | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
| [data-orientation] | "vertical" | "horizontal" | 
Track 
The track that contains the SliderRange.
| Prop | Default | Type | 
|---|---|---|
| as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
| [data-orientation] | "vertical" | "horizontal" | 
Range 
The range part. Must live inside SliderTrack.
| Prop | Default | Type | 
|---|---|---|
| as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
| [data-orientation] | "vertical" | "horizontal" | 
Thumb 
A draggable thumb. You can render multiple thumbs.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
| [data-orientation] | "vertical" | "horizontal" | 
Examples 
Vertical orientation 
Use the orientation prop to create a vertical slider.
// 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>/* 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.
// 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.
// 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.
// 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 
| Key | Description | 
|---|---|
| ArrowRight |  Increments/decrements by the  stepvalue depending onorientation. | 
| ArrowLeft |  Increments/decrements by the  stepvalue depending onorientation. | 
| ArrowUp |  Increases the value by the  stepamount. | 
| ArrowDown |  Decreases the value by the  stepamount. | 
| 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 
<script setup lang="ts">
import { Slider } from './your-slider'
</script>
<template>
  <Slider :default-value="[25]" />
</template>Implementation 
// your-slider.ts
export { default as Slider } from 'Slider.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:
<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.).