Components

Slider

Range input for a single value or a two-thumb range. Radix-powered with Yuno-token chrome: 6px track (bg-muted, rounded-full), primary-filled range, 16px circular thumb (1px border-primary, bg-background, shadow-sm). Hover and focus reveal a 4px muted ring around the thumb. Supports both horizontal and vertical orientation.

Updated Jul 17, 2026 by Leonardo Posada

Anatomy

Four parts. The Root manages state + keyboard; the Track is the 6px rail; the Range is the filled portion between (or before) the thumbs; each Thumb is a 16px draggable circle.

  1. 1
    Slider (Root)

    The container. Manages state (defaultValue / value + onValueChange), constraints (min / max / step), orientation ('horizontal' by default, 'vertical' for column layouts), and keyboard nav. flex items-center by default; flex-col + h-full when orientation='vertical'.

  2. 2
    SliderTrack

    The rail: h-1.5 (6px) w-full bg-muted rounded-full overflow-hidden. Swaps to h-full w-1.5 in vertical mode via data-[orientation=vertical]. Never override to a taller/thicker rail — 6px is the Yuno spec.

  3. 3
    SliderRange

    The filled portion, positioned absolute inside the Track. bg-primary. For a single-value slider it fills from left to the thumb; for range mode it fills between the two thumbs.

  4. 4
    SliderThumb

    The draggable handle: size-4 (16px), rounded-full, 1px border-primary, bg-background, shadow-sm. cursor-grab idle, cursor-grabbing while dragging. Hover/focus reveal a 4px ring-ring/40. Radix renders one Thumb per value in the array (single value → 1 thumb, range → 2 thumbs).

Variants

Two orthogonal axes: single value vs range, and horizontal vs vertical. Set defaultValue as an array with one element for single-value or two for range. Set orientation on the Root to switch axes.

Single value
<Slider defaultValue={[42]} max={100} step={1} />
Range (two thumbs)
<Slider defaultValue={[20, 80]} max={100} step={1} />
Vertical
<div className="h-40">
  <Slider
    orientation="vertical"
    defaultValue={[60]}
    max={100}
    step={1}
  />
</div>
Vertical range
<div className="h-40">
  <Slider
    orientation="vertical"
    defaultValue={[25, 75]}
    max={100}
    step={5}
  />
</div>

States

Track: idle (bg-muted). Range: bg-primary — grows/shrinks with the value. Thumb: idle (border + shadow-sm, cursor-grab), hover (4px ring-ring/40), focus-visible (same 4px ring — keyboard driven), dragging (cursor-grabbing + range follows), disabled (opacity-50, pointer-events-none, cursor-not-allowed).

6px rail, 16px thumb, 4px ring — don't drift
The Yuno slider spec is deliberately tight: 6px track, 16px thumb, 1px primary border, 4px muted ring on hover / focus. Every extra pixel makes the control feel heavier than it should. Override widths and heights for the container only — never the track height or thumb size.

Recipes

Ready-to-copy compositions covering the most common Yuno usages of this atom.

With label + live value

Standard pattern for settings and prototypes: a Label + a live-updating value on the right. State lives in the parent; onValueChange writes back.

42
const [value, setValue] = React.useState([42]);

<div className="space-y-3">
  <div className="flex items-center justify-between">
    <Label>Value</Label>
    <span className="text-sm tabular-nums text-muted-foreground">
      {value[0]}
    </span>
  </div>
  <Slider value={value} onValueChange={setValue} max={100} step={1} />
</div>
Range filter (two thumbs)

Two-thumb slider for range filters (price range, date window, amount bounds). Provide defaultValue as [min, max] with two elements — Radix renders two thumbs automatically. Show both endpoint labels.

2080
0100
const [range, setRange] = React.useState([20, 80]);

<div className="space-y-3">
  <div className="flex items-center justify-between">
    <Label>Range</Label>
    <span className="text-sm tabular-nums text-muted-foreground">
      {range[0]} – {range[1]}
    </span>
  </div>
  <Slider value={range} onValueChange={setRange} max={100} step={5} />
  <div className="flex justify-between text-xs text-muted-foreground">
    <span>0</span>
    <span>100</span>
  </div>
</div>
Stepped slider (snapped values)

Set step to force the thumb to snap to fixed increments (5 for percentages, 10 for weights). Useful when the value doesn't need pixel precision.

<Slider defaultValue={[50]} max={100} step={10} />
Vertical (volume / equalizer)

Set orientation='vertical' + a fixed height (h-40 h-48 etc.) on the parent. Common for volume controls, equalizer bands, or side-panel sliders. Radix flips arrow-key mapping to up/down automatically.

<div className="h-48">
  <Slider
    orientation="vertical"
    defaultValue={[70]}
    max={100}
    step={1}
  />
</div>

Import

One import from @/components/ui/slider.

Everything else — Label, value display — is composition.
import { Slider } from "@/components/ui/slider";

Props

Slider forwards all Radix Root props. The most useful for prototypes:

PropTypeDefaultDescription
defaultValuenumber[]Uncontrolled initial value. Single value → [42]; range → [20, 80]. Radix renders one thumb per array element.
value / onValueChangenumber[] / (value: number[]) => voidControlled pair. Use for live-updating labels or when the state needs to live in the parent.
min / maxnumber0 / 100Range bounds. max is exclusive of nothing — the thumb reaches it.
stepnumber1Increment the thumb snaps to. Match the granularity your UI displays — no reason to allow 42.7 if the label rounds to whole numbers.
orientation"horizontal" | "vertical""horizontal"Layout axis. Vertical requires an explicit container height (h-40, h-48) — Radix cannot infer it. Arrow-key mapping flips to up/down automatically.
disabledbooleanfalseLocks the slider. Opacity drops to 50, pointer-events disable, cursor becomes not-allowed.
invertedbooleanfalseReverses the direction. Rare in prototypes — use only when the surface's mental model is genuinely inverted (e.g. progress-remaining instead of progress-complete).
classNamestringMerged onto the Root. Use for container sizing (max-w-md, w-full). Do not override the track height or thumb size.

When to use

  • Filters over a continuous range (price, weight, threshold, amount bounds).
  • Settings sliders (volume, brightness, playback speed).
  • Any value where 'approximately X' is enough — precise entry is a separate control.

When not to use

  • Precise numeric input (amounts to two decimals) — use Input type='number'.
  • Discrete option sets (S / M / L) — use ToggleGroup or a Select.
  • Read-only display of a value — use Progress or a plain badge, never a locked Slider.

Usage

Do
  • Show the current value inline (either the live number or an anchored label) so the user reads without guessing.
  • Set a sensible step so the thumb snaps to meaningful increments — nothing worse than a slider stopping at 42.7183 when the surface only shows whole numbers.
  • For range mode, always show both endpoint values.
  • For vertical, give the container an explicit height (h-40, h-48) — Radix can't infer it.
  • Keep the track height at 6px and the thumb at 16px — the Yuno spec is deliberate.
Don't
  • Don't tint the track or the range — bg-muted and bg-primary are the only allowed values.
  • Don't inflate the thumb past size-4 (16px) — bigger thumbs feel toy-like at Dashboard density.
  • Don't hide the min/max endpoints when the range is arbitrary (0-100 with no context).
  • Don't wire Slider to a read-only value — use Progress.
  • Don't stack two sliders vertically without labels — the second one gets ignored.

Related

Cross-links to atoms and patterns you may reach for next.

  • InputReach for Input type='number' when the user needs pixel-precision (typing 42.37) — Slider is for approximate/coarse selection.
  • ProgressProgress reports a value; Slider lets the user set one. Never wire a Slider read-only to display a value — use Progress.
  • SwitchFor binary on/off — Slider is overkill.
  • Toggle groupFor discrete option sets (S / M / L) — Slider is for continuous ranges.