Slider
A single-thumb slider for selecting a numeric value within a range. It is built on top of the Range component, and exposes the same behavior through a single-value API.
import { Slider } from "@tenstorrent/vesper/slider";
export default function SliderDemo() {
return <Slider thumbAriaLabel="Volume" defaultValue={50} />;
}Options
| Prop | Type | Description | Default |
|---|---|---|---|
thumbAriaLabel | string | The accessible aria-label for the thumb. Required. | — |
value | number | The value of the thumb (controlled mode). | — |
defaultValue | number | The initial thumb value (uncontrolled mode). | min |
onValueChange | (value: number) => void | Callback fired as the thumb value changes during interaction. | — |
onValueCommit | (value: number) => void | Callback fired when the thumb interaction is completed, eg. on pointer up. | — |
min | number | The minimum allowed value. | 0 |
max | number | The maximum allowed value. | 100 |
step | number | The stepping interval between selectable values. | 1 |
showTicks | boolean | When true, renders tick marks along the track at each step interval. | false |
showValueLabel | boolean | When true, displays a value label above the thumb. | false |
valueLabel | string | A custom display label for the thumb. When unset, it falls back to the thumb's current value. | — |
disabled | boolean | When true, prevents interaction. | false |
name | string | The form field name submitted with form data. | — |
form | string | Associates the slider with a <form> element by its id. | — |
All other props are forwarded to the wrapping <div> element.
If you need to select a span of values rather than a single one, reach for the Range component instead: it renders the same track, but with a thumb per value.
Examples
Uncontrolled vs controlled
Render a Slider in an uncontrolled fashion to let it keep track of its own value. Pass defaultValue if the thumb should start somewhere other than min:
import { Slider } from "@tenstorrent/vesper/slider";
export default function UncontrolledSlider() {
return <Slider defaultValue={30} thumbAriaLabel="Volume" />;
}If you need to control the value, use the value and onValueChange props. onValueChange fires continuously as the thumb is dragged:
import { useState } from "react";
import { Slider } from "@tenstorrent/vesper/slider";
export default function ControlledSlider() {
const [volume, setVolume] = useState(75);
return (
<Slider value={volume} onValueChange={setVolume} thumbAriaLabel="Volume" />
);
}Use onValueCommit when you only care about the final value of an interaction, eg. to avoid firing a request on every pointer move:
import { Slider } from "@tenstorrent/vesper/slider";
export default function VolumeSlider() {
return (
<Slider
defaultValue={50}
onValueCommit={(volume) => savePreference({ volume })}
thumbAriaLabel="Volume"
/>
);
}Bounds and stepping
min, max, and step describe the values the thumb can take, defaulting to 0, 100, and 1. A step of 100 on a range of 0-1000 restricts the thumb to multiples of 100:
import { Slider } from "@tenstorrent/vesper/slider";
export default function LargeStepSlider() {
return (
<Slider
min={0}
max={1000}
step={100}
defaultValue={500}
showValueLabel
thumbAriaLabel="Budget"
/>
);
}The step also determines how far the thumb moves per arrow key press when it is focused.
value nor defaultValue is provided, the thumb starts at min rather than at zero, so a slider with a min of 10 starts at 10.Showing ticks
Pass showTicks to mark each step along the track. Ticks are rendered between min and max, so a range of 0-10 with a step of 1 renders nine of them:
import { Slider } from "@tenstorrent/vesper/slider";
export default function SliderWithTicks() {
return (
<Slider
min={0}
max={10}
step={1}
showTicks
defaultValue={3}
thumbAriaLabel="Rating"
/>
);
}step on a wide range produces a dense, noisy track. Ticks work best when the range has a handful of stops, eg. a range of 0-100 with a step of 10.Value label
Pass showValueLabel to render the thumb's current value above it as you drag:
import { Slider } from "@tenstorrent/vesper/slider";
export default function SliderWithVisibleValueLabel() {
return <Slider showValueLabel defaultValue={40} thumbAriaLabel="Volume" />;
}Use valueLabel to display something other than the raw value, such as a formatted or unit-suffixed one. It is only rendered when showValueLabel is also passed:
import { useState } from "react";
import { Slider } from "@tenstorrent/vesper/slider";
export default function SliderWithCustomValueLabel() {
const [volume, setVolume] = useState(40);
return (
<Slider
showValueLabel
value={volume}
onValueChange={setVolume}
valueLabel={`${volume}%`}
thumbAriaLabel="Volume"
/>
);
}thumbAriaLabel too.Keyboard interaction
The thumb is a native <input type="range">, so a Slider is fully keyboard operable once it is focused:
| Key | Behaviour |
|---|---|
ArrowRight / ArrowUp | Increases the value by step. |
ArrowLeft / ArrowDown | Decreases the value by step. |
Shift + any arrow key | Moves the thumb by 10 units instead of step. |
PageUp / PageDown | Increases / decreases the value by 10 units. |
Home | Moves the thumb to min. |
End | Moves the thumb to max. |
Disabling the slider
Pass disabled to prevent all interaction. A disabled Slider still displays its current value, but its thumb is skipped in the tab order and excluded from form data:
import { Slider } from "@tenstorrent/vesper/slider";
export default function DisabledSlider() {
return <Slider disabled defaultValue={50} thumbAriaLabel="Volume" />;
}Usage in forms
The thumb renders a native <input type="range">, so passing a name includes its value in form submissions. Use the form prop to associate the field with a <form> rendered elsewhere on the page:
import { useState } from "react";
import { Button } from "@tenstorrent/vesper/button";
import { Slider } from "@tenstorrent/vesper/slider";
import { Typography } from "@tenstorrent/vesper/typography";
export default function FormSliderDemo() {
const [submitted, setSubmitted] = useState<string | null>(null);
return (
<form
style={{
display: "flex",
flexDirection: "column",
gap: "var(--vesper-spacing-4)",
}}
onSubmit={(event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
setSubmitted(String(data.get("volume") ?? ""));
}}
>
<Slider name="volume" defaultValue={50} thumbAriaLabel="Volume" />
<Button size="sm" type="submit">
Submit
</Button>
{submitted !== null && (
<Typography variant="copy-sm">Submitted value: {submitted}</Typography>
)}
</form>
);
}A range input always has a value, so a Slider submits its current value even if the user never touches it. The form above submits volume=50 on an untouched slider.