motif svelteArc

Slider ported

Pick a value or a range on a track that follows your finger.

Pick a value or a range on a track that follows your finger.

Live specimen

Loading demo…

Guidance

When to use

  • Approximate values like volume, opacity, or a price range.
  • Ranges with two thumbs, labelled marks, and a formatted readout.

When not to use

  • Use number-field when the exact number matters.
  • Use progress to show a value people cannot change.

Installation

pnpm dlx shadcn-svelte@latest add @arcui/slider

Usage

<script lang="ts">
  import { Slider } from '$lib/components/slider';

  let volume = $state(40);
</script>

<Slider label="Volume" bind:value={volume} />

Variants & Examples

Single value

Bind a number. Omit value and pass defaultValue for uncontrolled use.

<Slider label="Volume" bind:value={volume} />

Range

Bind a [low, high] tuple to get two thumbs. minStepsBetweenThumbs keeps them apart.

<Slider label="Budget" bind:value={range} step={5} minStepsBetweenThumbs={2} thumbLabels={['Minimum price', 'Maximum price']} />

Marks

A bare number draws a tick. A mark with a label prints under the track, and clicking it moves the nearest thumb there.

<Slider label="Size" step={25} defaultValue={50} marks={[{ value: 0, label: 'S' }, 50, { value: 100, label: 'L' }]} />

Start and end snippets

Place content beside the track, such as an icon.

<Slider label="Volume" bind:value={volume}>
  {#snippet start()}<VolumeIcon />{/snippet}
</Slider>

API Reference

PropTypeDefaultDescription
valueT extends number | [number, number]–Bindable. A number for one thumb, a tuple for a range. Leave unset for uncontrolled use.
defaultValueT–Initial value when uncontrolled. Its shape (number or tuple) decides single or range.
marks(number | { value: number; label?: string })[]–Ticks on the track. A labelled mark also prints under the track and is clickable.
labelstring–(Required) Visible label; names the thumbs unless thumbLabels is set.
onValueChange(value: T) => void–Called on every step while dragging or pressing keys.
onValueCommit(value: T) => void–Called once when a drag is released or a key changes the value.
minnumber'0'Lower bound.
maxnumber'100'Upper bound.
stepnumber'1'Increment.
largeStepnumber'a tenth of the range'Distance for PageUp, PageDown, and Shift with an arrow.
minStepsBetweenThumbsnumber'0'Closest two range thumbs may sit, in steps.
format(value: number) => string–Formats the readout, bubble, and spoken value.
showValueboolean'true'Show the readout beside the label.
thumbLabels[string, string]–Accessible names for the two range thumbs.
startSnippet–Content before the track, such as an icon.
endSnippet–Content after the track.
namestring–Submits the value with a form, one hidden input per thumb.
disabledboolean–Disables dragging and keys.
classNamestring–Added to the root.

Keyboard Interactions

KeyAction
ArrowRight / ArrowUpIncreases by step.
ArrowLeft / ArrowDownDecreases by step.
Shift + Arrow / PageUp / PageDownMoves by largeStep.
Home / EndMoves to the lowest or highest allowed value for that thumb.

Accessibility

  • Each thumb is role="slider" with aria-valuemin, aria-valuemax, aria-valuenow, aria-valuetext from format, and aria-orientation.
  • Thumbs are named by label, or by thumbLabels for ranges.
  • The readout, bubble, and marks are aria-hidden because the thumbs carry the value.

Motion

Phase 1 (current): the thumb, fill, and readout jump straight to the stepped value; the bubble appears and disappears without animation. Phase 2 (React behaviour): - Released drags carry a little momentum before snapping; the bubble springs up over an active thumb and digits roll in the readout. At a limit the thumb strains toward the key press and springs back. - Reduced motion removes momentum, the strain, and digit rolling, and turns off CSS transitions.

Notes for AI

  • Use for approximate values and ranges like volume, price filters, or opacity. Use number-field when the exact number matters.
  • Controlled or uncontrolled; pass a tuple for a range. Put heavy work such as fetching in onValueCommit, not onValueChange.
  • Pass name to submit through hidden inputs. Exported as a named export: import { Slider } from '$lib/components/slider'.

Source of truth: registry/components/slider/slider.tsx