Slider

A range input. Underneath, a native input with type range, a filled track and a thumb.

Usage

The slider is only the control: pair it with a Label and show the value where it fits your layout.

tsx
const [volume, setVolume] = useState(70);

<div className="flex items-baseline justify-between">
  <Label spaced htmlFor="volume">volume</Label>
  <span className="text-xs text-medium tabular-nums">{volume}%</span>
</div>
<Slider id="volume" value={volume} onChange={(event) => setVolume(event.target.valueAsNumber)} />
70%

Range and step

min, max and step are the native ones, so decimals work. Read the value with valueAsNumber, which is already a number.

tsx
const [volume, setVolume] = useState(1);

<Slider
  min={0}
  max={1.5}
  step={0.01}
  value={volume}
  onChange={(event) => setVolume(event.target.valueAsNumber)}
  onDoubleClick={() => setVolume(1)}
/>
100%

States

tsx
<Slider defaultValue={60} />
<Slider defaultValue={60} disabled />

Reference

proptypedefault
value?number—controlled, with onChange
defaultValue?number—uncontrolled
min?number0native
max?number100native
step?number1native
disabled?booleanfalsenative; dimmed
onChange?ChangeEventHandler—fires on every step while dragging
className?string—merged last, so it wins
…restprops of input—id, name, onDoubleClick and the rest; type is fixed

Tokens

token
--margo-slider-trackthe empty part of the track; border colour by default
--margo-slider-fillthe filled part of the track; primary by default
--margo-slider-thumbthe thumb; primary by default
--margo-slider-thumb-borderthe thumb's border; primary darken by default
--margo-slider-track-sizethe height of the track; 0.375rem by default
--margo-slider-thumb-sizethe size of the thumb; 1rem by default
--margo-slider-valuewhere the fill ends; written by the component, not by you