opsinjs
ComponentsActions and forms

Slider

A single coarse, non-clinical preference set by dragging a thumb along a track, and never a clinical reading or a precise measurement.

Preview

Theme
Density
Text
Status
slider · base base · style base-lyraOpen under the product theme

Installation

pnpm dlx shadcn@latest add @opsinjs/slider

The @opsinjs namespace is declared in your components.json. Everything it installs is code you then own. There is no runtime package to keep in step.

Usage

import { Slider } from "@/components/ui/slider"
<Slider
  label="Screen brightness"
  value={brightness}
  onValueChange={setBrightness}
/>

When to use it

Use it when

  • A coarse, non-clinical preference such as a brightness level, where the exact number does not matter.
  • A value adjusted by feel, where sliding towards more or less beats typing a figure.
  • A setting with a small set of stops the reader can actually mean.

Do not use it when

  • You are capturing a clinical reading. A slider turns a value the person meant into a value the pixel chose.Use reading-input instead.
  • You need a precise non-clinical quantity where the digits matter.Use number-field instead.
  • The reader picks one of a small set of named options rather than a point on a continuum.Use segmented-control instead.

Anatomy

  1. SliderThe root. Holds value, min, max and step, and sits on neither colour axis.Controlled by value
  2. Slider.LabelThe visible label, wired to the thumb's hidden input so it names the control.Controlled by label
  3. Slider.ValueA text readout mirroring the value, quieter than the label, with tabular figures.
  4. Slider.ControlThe pointer region. Floors its height at the target minimum and blocks touch scrolling.
  5. Slider.TrackThe thin muted rail with a hairline.
  6. Slider.IndicatorThe filled portion, from the track start to the thumb, in the bridged primary role.
  7. Slider.ThumbThe draggable knob. A 44px hit area nesting a real range input.Controlled by disabled
  • Slider 1
    • Slider.Label 1
    • Slider.Value 1
    • Slider.Control 1
      • Slider.Track 1
        • Slider.Indicator 1
        • Slider.Thumb 1

Examples

A coarse preference

A fictional notification volume from nought to a hundred, driven by value and onValueChange.

Theme
Density
Text
Status
slider-a-coarse-preference · base base · style base-lyraOpen under the product theme

With steps

min, max and step snap the thumb to stops: a fictional map zoom running from one to nine in twos.

Theme
Density
Text
Status
slider-with-steps · base base · style base-lyraOpen under the product theme

Content guidelines

Name the preference, not the gesture: Screen brightness, never Drag to set brightness. The label is the accessible name and is heard before the value. Keep units out of the readout, because a unit invites the reader to treat a rough position as a measurement.

Do

"Screen brightness" with a bare nought to a hundred readout names the thing adjusted.

Don’t

"Blood pressure" with a mmHg readout dresses a rough position as a measurement.

Accessibility

This component was audited against WCAG 2.2 AA in a source pass and a rendered pass. The audit is author-run, it is not an independent review, and clinical review is still pending. The rendered pass was clean: no axe violations, no target-size breach and no reflow failure. The source already handled the flagged risks, so nothing changed here.

  • 2.5.7 Dragging: the thumb wraps Base UI unmodified, so click-to-position plus Arrow, Home, End and Page keys give every drag a keyboard alternative.
  • 4.1.2 Name, Role, Value: role, aria-valuenow, min and max come from the nested real range input, and the Slider.Label text is forwarded onto it so the name is present at render.
  • 2.5.8: the thumb hit area is floored at --opsin-target-minimum on both axes, with the knob drawn smaller inside.

Two residual items. The knob's colour fade on interaction has no reduced-motion guard, but it is a colour change and not positional motion, so any neutralisation belongs in a shared stylesheet. The Slider.Value readout renders as an output with a polite live region, so while dragging the value is spoken twice, a verbosity and not a defect. Contrast pairs remain unmeasured.

KeyActionNotes
TabMoves focus onto the thumbOne tab stop, on the thumb's nested range input.
Shift+TabMoves focus back out of the controlA single stop in reverse too.
Arrow Right, Arrow UpIncreases the value by one stepThe `step` prop. A right-to-left layout swaps Left and Right.
Arrow Left, Arrow DownDecreases the value by one stepThe `step` prop, and the value stops at `min`.
HomeSets the value to the minimumJumps the thumb to the start.
EndSets the value to the maximumJumps the thumb to the end.
Page Up, Page DownIncreases or decreases by a larger stepBase UI's default of ten, not the `step` prop.
PairThemeAPCA LcWCAG 2.2Floor
body text on the pagelight101.617.18:1Pass
body text on the pagedark-100.518.00:1Pass
body text on a cardlight104.717.96:1Pass
body text on a carddark-99.616.32:1Pass
body text on the muted groundlight98.116.32:1Pass
body text on the muted grounddark-97.513.77:1Pass
secondary text on the pagelight83.97.42:1Pass
secondary text on the pagedark-80.713.44:1Pass
secondary text on a cardlight87.07.76:1Pass
secondary text on a carddark-79.812.19:1Pass
secondary text on the muted groundlight80.47.05:1Pass
secondary text on the muted grounddark-77.810.28:1Pass
a hairline boundary on the pagelight19.31.41:1Below floor
a hairline boundary on the pagedark-8.21.90:1Below floor
a hairline boundary on a cardlight22.41.47:1Below floor
a hairline boundary on a carddark-7.31.72:1Below floor
a hairline boundary on the muted groundlight15.81.34:1Below floor
a hairline boundary on the muted grounddark0.01.45:1Below floor
a placeholder boundary on the pagelight69.84.52:1Pass
a placeholder boundary on the pagedark-51.07.62:1Pass
a placeholder boundary on a cardlight72.84.72:1Pass
a placeholder boundary on a carddark-50.16.91:1Pass
a placeholder boundary on the muted groundlight66.24.29:1Pass
a placeholder boundary on the muted grounddark-48.15.83:1Pass
a placeholder fill on the pagelight8.31.18:1Below floor
a placeholder fill on the pagedark-8.21.90:1Below floor
a placeholder fill on a cardlight11.41.23:1Below floor
a placeholder fill on a carddark-7.31.72:1Below floor
a placeholder fill on the muted groundlight0.01.12:1Below floor
a placeholder fill on the muted grounddark0.01.45:1Below floor
a placeholder boundary on its own filllight58.93.84:1Pass
a placeholder boundary on its own filldark-41.54.01:1Below floor
the card hairline on the pagelight69.84.52:1Pass
the card hairline on the pagedark-28.74.19:1Below floor
the card hairline on a cardlight72.84.72:1Pass
the card hairline on a carddark-27.93.80:1Below floor

These are the measured token pairs this component draws colour from, not a measurement of the component itself.

API reference

Prop

Type

Generated from SliderProps in registry/bases/base/slider.tsx.

value and onValueChange make this controlled, so the caller holds the number. label is required and a missing one raises a development warning. min defaults to 0, max to 100 and step to 1.

  • ReadingInput is where a clinical measurement is typed, with the unit and the plausibility checks.
  • NumberField is for a precise non-clinical quantity where the digits matter.
  • SegmentedControl picks a named option rather than a value along a continuum.

On this page