Slider
Overviewimport { Slider, SliderValue } from '@nili/ui';This is the library’s own overview page, rendered live. Switch the language or the theme in the header and it follows.
Single thumb and range
The shape of the value is the type: a number renders one thumb, a [number, number] renders a range. A range slider cannot be handed a single number by accident.
import { Slider } from "@nili/ui"
export function Example() {
const [value, setValue] = useState(40)
const [range, setRange] = useState([20, 70])
return (
<>
<Slider
label="Volume"
value={value}
onValueChange={setValue}
showValue
/>
<Slider
label="Price"
value={range}
onValueChange={setRange}
showValue
/>
</>
)
}Label, sublabel and value
label names the thumbs as well as showing above the track. showValue puts the current number beside it; sublabel adds a muted second line.
import { Slider } from "@nili/ui"
export function Example() {
return (
<>
<Slider label={t('brightness')} defaultValue={60} />
<Slider label="Brightness" sublabel="Screen only" defaultValue={60} showValue />
{/* no visible label — name the thumbs instead */}
<Slider defaultValue={60} thumbLabels={["Brightness"]} />
</>
)
}Tooltip
tooltip shows the value in a bubble above the thumb while dragging — useful when there is no room for a permanent readout.
import { Slider } from "@nili/ui"
export function Example() {
return <Slider label={t('opacity')} defaultValue={75} tooltip />
}Steps and bounds
min, max and step behave as you would expect. minStepsBetweenThumbs keeps the two ends of a range from crossing.
import { Slider } from "@nili/ui"
export function Example() {
return (
<>
<Slider label="Rating" min={1} max={5} step={1} defaultValue={3} showValue />
<Slider label="Temperature" min={-20} max={50} step={5} defaultValue={20} showValue />
<Slider
label="Budget"
min={0}
max={1000}
step={50}
defaultValue={[200, 600]}
minStepsBetweenThumbs={2}
showValue
/>
</>
)
}Formatting
formatValue changes every number the user sees or hears, not only the visible one. Digits follow the ambient locale by default, so a Persian UI gets Persian numerals for free.
import { Slider } from "@nili/ui"
export function Example() {
return (
<>
<Slider
label="Storage"
max={500}
defaultValue={120}
showValue
formatValue={(value) => `${value} GB`}
/>
<Slider
label="Discount"
defaultValue={25}
showValue
formatValue={(value) => `${value}%`}
/>
</>
)
}Commit and disabled
onValueChange fires on every step while dragging; onValueCommit fires once, when the pointer or key is released. Use the second for anything expensive — a request per pixel of drag is the usual way a slider takes a server down.
import { Slider } from "@nili/ui"
export function Example() {
return (
<>
<Slider
label="Results per page"
defaultValue={20}
max={100}
step={10}
showValue
onValueCommit={(value) => refetch(value)}
/>
<Slider label="Disabled" defaultValue={40} disabled />
</>
)
}Slider
extends Omit< ComponentPropsWithoutRef<'div'>, 'onChange' | 'defaultValue' | 'color' >
Other props
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | — | |
| aria-label | string | — | |
| value | SliderValue | — | Controlled value. A `number` renders one thumb, a `[number, number]` renders a range — the shape of the value *is* Figma's "Type", so a range slider cannot be handed a single number by accident. |
| defaultValue | SliderValue | 0 | |
| onValueChange | (value: SliderValue) => void | — | Fires on every step while dragging. |
| onValueCommit | (value: SliderValue) => void | — | Fires once, when the pointer or key is released. Use this for anything expensive — a request per pixel of drag is the usual way a slider takes a server down. |
| min | number | 0 | |
| max | number | 100 | |
| step | number | 1 | |
| minStepsBetweenThumbs | number | 0 | Smallest allowed gap between the two thumbs of a range. |
| disabled | boolean | false | |
| label | ReactNode | — | Visible label above the track. Also names the thumbs. Figma's "Label". |
| sublabel | ReactNode | — | Muted second line under the label. Figma's "Sublabel". |
| showValue | boolean | false | Shows the current value beside the label. Figma's "Edit Amount". |
| tooltip | boolean | false | Value bubble above the thumb while dragging. Figma's "Tooltip". |
| formatValue | (value: number) => string | — | Formats every number the user sees or hears. Defaults to localized digits. |
| locale | string | — | BCP-47 tag driving the digits (`'fa'` → Persian). Defaults to the ambient locale from `NiliProvider`. |
| dir | ltr | rtl | — | Forces the drag direction, overriding the ambient locale. Needed for a track whose axis is not the reading axis — a video timeline runs from the video's start to its end, which is not a sentence, so it is pinned `ltr` even in a Persian UI. Without this the CSS renders one way and the pointer maths mirrors the other, and the playhead jumps backwards. |
| thumbLabels | [string, string?] | — | Accessible names for the thumbs, when there is no visible `label`. |
| name | string | — | `name` for the hidden inputs, when the form is submitted natively. |
SliderHeader
internalSliderRange
internalSliderRoot
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| disabled | 'true' | 'false' | false |
SliderThumb
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| disabled | 'true' | 'false' | false |
SliderTooltip
internalSliderTrack
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| disabled | 'true' | 'false' | false |