Skip to main content
Vuetify0 is now in alpha!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Slider

Headless slider for single-value and range inputs with pointer drag, keyboard navigation, and step snapping.


Renders elementIntermediateApr 5, 2026

Usage

The Slider supports single-value and range modes. Add one Slider.Thumb for a single value, or two for a range.

Single and Range Slider

A single-value slider and a range slider with track and thumb components.

Value: 50

Range: 25 – 75

Anatomy

vue
<script setup lang="ts">
  import { Slider } from '@vuetify/v0'
</script>

<template>
  <!-- Single thumb -->
  <Slider.Root>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
  </Slider.Root>

  <!-- Range (two thumbs) -->
  <Slider.Root>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
    <Slider.Thumb />
  </Slider.Root>

  <!-- With form submission -->
  <Slider.Root>
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />

    <Slider.HiddenInput />
  </Slider.Root>
</template>

Architecture

The Root component composes createSlider for pointer/keyboard interaction and createModel for value storage. Each Thumb registers via a ticket and receives its position as a percentage.

Slider Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Slider Architecture

The Root creates a slider instance and provides it via context. Track listens for pointer events to update the nearest thumb. Each Thumb registers itself and manages drag/keyboard interaction for its value. Range renders the filled region between thumbs (or from min to a single thumb).

Examples

Audio Equalizer

Multiple vertical sliders composed into a 5-band equalizer with preset management. Each band is an independent Slider.Root with orientation="vertical", bridged to a shared gains array via @update:model-value.

File breakdown:

FileRole
useEqualizer.tsComposable — band definitions, gain state, named presets, apply() and reset()
Equalizer.vueReusable component — renders one vertical Slider per band with dB scale and frequency labels
equalizer.vueDemo — wires preset buttons to the composable

Key patterns:

  • Slider.Thumb v-slot="{ value, isDragging }" drives both the scale animation and the floating dB label that appears only while dragging

  • Each band’s Slider.Root receives a single-element array ([gains[index]]) and writes back via an update function that splices into the shared array

  • The composable owns all state — the component is purely presentational, making it reusable with different band configurations

+120-12
0
60
0
250
0
1k
0
4k
0
16k

HSL Color Picker

Three sliders for Hue, Saturation, and Lightness with reactive gradient tracks and a live color preview. Demonstrates how to hide Slider.Range when the track gradient is the visualization.

File breakdown:

FileRole
ColorSlider.vueReusable gradient slider — accepts a gradient prop for the track background and thumbColor for dynamic thumb styling
ColorPicker.vueComposes three ColorSliders with reactive gradients that update when hue changes, plus a color swatch and hex output
color-picker.vueDemo — adds clickable color presets that set all three models at once

Key patterns:

  • Slider.Range is omitted entirely — the gradient track replaces it as the visual indicator

  • Slider.Thumb uses data-[state=dragging]:scale-125 for drag feedback without needing slot props — the component sets left automatically via its internal attrs.style

  • Saturation and lightness gradients are toRef derivations that recompute when hue changes, making the tracks shift color in real time

  • defineModel with named models (v-model:hue, v-model:saturation, v-model:lightness) gives the parent fine-grained control over each channel

HSL220°, 80%, 55%HEX#306ee8
Hue220
Saturation80
Lightness55
Presets

Recipes

Form Integration

Set name on Root to auto-render hidden inputs for form submission — one per thumb:

vue
<template>
  <Slider.Root name="price" :min="0" :max="1000">
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
  </Slider.Root>
</template>

Drag Events

Root emits start and end for pointer drag lifecycle:

vue
<template>
  <Slider.Root
    v-model="value"
    @start="onStart"
    @end="onEnd"
  >
    <Slider.Track>
      <Slider.Range />
    </Slider.Track>

    <Slider.Thumb />
  </Slider.Root>
</template>

Data Attributes

Style interactive states without slot props:

vue
<template>
  <Slider.Thumb class="data-[state=dragging]:scale-125 transition-transform" />
</template>
AttributeValuesComponents
data-statedragging, idleThumb
data-disabledtrueRoot, Track, Range, Thumb
data-readonlytrueRoot, Track, Range, Thumb
data-orientationhorizontal, verticalRoot, Track, Range

Accessibility

Each Slider.Thumb manages its own ARIA attributes automatically.

ARIA Attributes

AttributeValueNotes
rolesliderApplied to each Thumb
aria-valuenowCurrent valueUpdates on drag/keyboard
aria-valueminMin valueFrom Root’s min prop
aria-valuemaxMax valueFrom Root’s max prop
aria-valuetextCustom textOptional, via Thumb prop
aria-orientationhorizontal / verticalReflects Root orientation
aria-disabledtrueWhen slider is disabled
aria-readonlytrueWhen slider is readonly
tabindex0 / removedRemoved when disabled

Keyboard Navigation

KeyAction
ArrowRight / ArrowUpIncrement by one step
ArrowLeft / ArrowDownDecrement by one step
Shift+ArrowIncrement/decrement by 10 steps
PageUpIncrement by 10 steps
PageDownDecrement by 10 steps
HomeSet to minimum
EndSet to maximum

API Reference

The following API details are for all variations of the Slider component.

Slider.Root

Props

id

string | undefined

Unique identifier (auto-generated if not provided)

Default: useId()

min

number | undefined

Minimum value (default: 0)

Default: 0

max

number | undefined

Maximum value (default: 100)

Default: 100

step

number | undefined

Step increment (default: 1)

Default: 1

disabled

MaybeRefOrGetter<boolean> | undefined

Disables the slider

Default: false

readonly

MaybeRefOrGetter<boolean> | undefined

Readonly — focusable but not editable

orientation

"horizontal" | "vertical" | undefined

Slider orientation

Default: "horizontal"

inverted

boolean | undefined

Flip the percent axis

Default: false

minStepsBetweenThumbs

number | undefined

Minimum steps between adjacent thumbs (default: 0)

Default: 0

crossover

boolean | undefined

Allow thumbs to pass through each other (default: false)

Default: false

name

string | undefined

Form field name — triggers hidden inputs

form

string | undefined

Associate with form by ID

namespace

string | undefined

Namespace for context provision

Default: "v0:slider:root"

modelValue

number | number[] | undefined

Default: []

Events

update:model-value

[value: number | number[]]

start

[value: number | number[]]

end

[value: number | number[]]

Slots

default

SliderRootSlotProps

Slider.HiddenInput

Props

namespace

string | undefined

Namespace for context injection from parent Slider.Root

Default: "v0:slider:root"

index

number | undefined

Thumb index to read value from

Default: 0

Slider.Range

Props

namespace

string | undefined

Namespace for connecting to parent Slider.Root

Default: "v0:slider:root"

Slots

default

SliderRangeSlotProps

Slider.Thumb

Props

namespace

string | undefined

Namespace for connecting to parent Slider.Root

Default: "v0:slider:root"

ariaLabel

string | undefined

Accessible label for this thumb

ariaLabelledby

string | undefined

ID of element labelling this thumb

ariaValuetext

string | undefined

Custom aria-valuetext (for formatted display)

Slots

default

SliderThumbSlotProps

Slider.Track

Props

namespace

string | undefined

Namespace for connecting to parent Slider.Root

Default: "v0:slider:root"

Slots

default

SliderTrackSlotProps
Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/