Stepwise UI

Slider

An inline field slider: a labelled squircle row with a thin handle and the live value, matching Input's corner radius and smoothing. Drag, click, or use the arrow keys. Comes in plain, dotted, and dual-handle range variants, plus a classical capsule-and-knob layout for when the field style isn't the fit; responsive and theme-aware.

Installation

npx stepwise-ui add slider

Default

Width40
import { Slider } from '@/components/stepwise/slider'

const [width, setWidth] = useState(40)

<Slider label="Width" value={width} onChange={setWidth} min={0} max={100} />

Dots

Tick marks split the track into steps. Each dot fades out as the fill passes it, so the handle reads its position at a glance - good for discrete, low-count settings.
Shape0
// "dots" adds evenly spaced tick marks; they fade as the fill passes them
<Slider variant="dots" label="Shape" value={v} onChange={setV}
        min={0} max={8} step={1} dotCount={9} />

Range

Two handles select a span; the fill sits between them and the handles can't cross.onChangereturns a [start, end] tuple.
Radius240 – 680
// "range" gives two handles and returns a [start, end] tuple
const [range, setRange] = useState<[number, number]>([240, 680])

<Slider variant="range" label="Radius" value={range} onChange={setRange}
        min={0} max={1000} />

Classical

Compact pill track, solid zinc fill, white knob inset equally on all four sides with a light shadow - no ring, no gradient. classical is orthogonal to variant: plain is continuous, dots adds fixed-interval ticks, range adds a second handle. Label and value sit above the track. Dots swap color instead of fading here - the capsule track is too compact for the fade to read.
Volume50%
Rating3
Price$20 – $75
// classical is orthogonal to variant - dots/range still apply on top of it.
// Label/value move above the track instead of overlaying it.
<Slider classical label="Volume" value={v} onChange={setV} formatValue={n => `${n}%`} />
<Slider classical variant="dots" label="Rating" value={r} onChange={setR} min={0} max={8} dotCount={9} />
<Slider classical variant="range" label="Price" value={p} onChange={setP} formatValue={n => `$${n}`} />

Showcase

Custom value formatting via formatValue.
Opacity64%
Weight3
Price$20 – $75
<Slider label="Opacity" value={a} onChange={setA} formatValue={n => `${n}%`} />
<Slider variant="dots" label="Weight" value={b} onChange={setB} min={0} max={6} dotCount={7} />
<Slider variant="range" label="Price" value={c} onChange={setC} formatValue={n => `$${n}`} />

Props

PropTypeDescription
variant
"plain" | "dots" | "range"
Track style. Default "plain".
classical
boolean
Compact pill-track layout instead of the field style. Default false.
orientation
"horizontal" | "vertical"
Classical track only. Default horizontal.
value
number | [number, number]
Controlled value (tuple for range).
defaultValue
number | [number, number]
Uncontrolled initial value.
onChange
(v: number | [number, number]) => void
Fires on drag / key / click.
min
number
Minimum. Default 0.
max
number
Maximum. Default 100.
step
number
Snap increment. Default 1.
label
string
Label shown inside, on the left.
showValue
boolean
Show the value on the right. Default true.
formatValue
(v: number) => string
Format the displayed value.
dotCount
number
Tick marks for the dots variant. Default 5.
disabled
boolean
Disables interaction.