Skip to content
Component installs need the registry setup
VegaStack Design

Slider

Pick a number or a range from a continuous track — horizontal or vertical, any number of thumbs, each with a 24px hit area.

Status
stable
Since
0.1.0
Accessibility pattern
APG slider

Last updated

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Slider before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify slider

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/slider

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

Usage

import { Slider } from "@/components/ui/slider";

<Slider defaultValue={[33]} max={100} step={1} />;

Anatomy

Slider — data-slot="slider" | "slider-range" | "slider-thumb" | "slider-track"

Examples

Range

Pass an array with two values for a range slider.

Multiple Thumbs

Pass an array with any number of values — the component renders one thumb per entry.

Vertical

Use orientation="vertical" and give the slider a height.

Controlled

Hold the value yourself with value and onValueChange.

0.3, 0.7

Disabled

Use the disabled prop. The control keeps its pointer events (FRM-4), so a Tooltip can explain why it is unavailable.

RTL

The track and the indicator are written with logical properties, so a right-to-left document fills from the other end.

Playground

Every Slider prop, auto-generated from the component's own types.

string

API Reference

Slider adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Accessibility

  • Renders Base UI's Slider, which gives every thumb role="slider" with aria-valuenow, aria-valuemin and aria-valuemax; ←/→, Home, End and PageUp/PageDown all move it.
  • The thumb is 12px, so an ::after pseudo-element extends its pointer target to 28×28 (A11Y-2), verified by a real elementFromPoint probe.
  • On :focus-visible the global 2px outline in base.css applies (FOC-1) — upstream's hover:ring-3 focus-visible:ring-3 active:ring-3 glow is gone (FOC-6).
  • A slider has no visible text of its own — give it an aria-label. That label reaches the hidden <input type="range"> that actually holds the role, which is what a screen reader announces. A Label htmlFor pointed at the Slider's id does not name it: the id lands on the root <div>, and the input keeps a generated one.
ContractStates tested
Behaviourdefault, range, vertical, disabled, dragging
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test, keyboard-navigation, disabled
Visualdefault, hover, focus, disabled

Do / Don't

Do
Use a Slider for an approximate value over a bounded range — volume, a price filter, a temperature.
Don't
Use a Slider where the user knows the exact number — that is a number input.

Deviations

Upstream's file plus packages/ui/upstream/patches/slider.patch. Every hunk:

  • FOC-1, FOC-6 — the thumb's ring-ring/50 colour and its three glow triggers (hover:ring-3, focus-visible:ring-3, active:ring-3) are removed, along with focus-visible:outline-hidden, which would have suppressed the global outline.
  • FRM-4 — disabled:pointer-events-none is dropped, so a disabled slider stays hoverable and a Tooltip can explain it.
  • A11Y-16 — the root's aria-label is forwarded to every thumb through getAriaLabel. Base UI keeps the real control in a visually hidden <input type="range"> inside the thumb, and a label on the root lands on a <div> with no role, so upstream's file ships a nameless role="slider" in every composition. A range slider gives both thumbs the group's name: upstream has no per-thumb label API.
  • DOC-2 — cn is imported from @vegastack/design.

On this page