Slider
Pick a number or a range by dragging, when about right is good enough.
Preview
tsx
import { state } from '@kerf-js/core'import { Slider } from '@kerf-js/veneer'export function Basic() { const copies = state(3) return ( <Slider label="Copies" value={copies.value} min={1} max={8} onChange={(v) => (copies.value = v)} /> )}const min = 60_000Installation
npm install @kerf-js/veneerTry it
Change the controls: the preview and its code update together. The address keeps what you set, so you can link to it.
Live preview
Controls
Min
Max
Step
Codeupdates as you change the controls
import { Slider } from '@kerf-js/veneer'<Slider value={v.value} onChange={next => (v.value = next)} label="Copies" min={1} max={12} />Usage
tsx
import { Slider } from '@kerf-js/veneer'Formatted value
format draws the number with its unit.
tsx
import { state } from '@kerf-js/core'import { Slider } from '@kerf-js/veneer'export function Format() { const memory = state(4) return ( <Slider label="Memory" value={memory.value} min={1} max={32} format={gigabytes} onChange={(v) => (memory.value = v)} /> )}const min = 60_000const gigabytes = (v: number) => `${v} GB`Steps
Use step to snap the value to fixed jumps, here every 25.
tsx
import { state } from '@kerf-js/core'import { Slider } from '@kerf-js/veneer'export function Step() { const rollout = state(25) return ( <Slider label="Rollout" value={rollout.value} step={25} format={percent} onChange={(v) => (rollout.value = v)} /> )}const percent = (v: number) => `${v}%`A range
Two numbers make two thumbs. names tells screen readers which is which.
tsx
import { state } from '@kerf-js/core'import { Slider } from '@kerf-js/veneer'export function Range() { const copies = state<[number, number]>([2, 6]) return ( <Slider label="Copies" value={copies.value} min={1} max={12} names={['Fewest copies', 'Most copies']} onChange={(v) => (copies.value = v)} /> )}const min = 60_000Disabled
Use disabled to show a value that cannot be changed.
tsx
import { Slider } from '@kerf-js/veneer'export function Disabled() { return ( <Slider label="Copies" value={3} min={1} max={8} disabled onChange={() => {}} /> )}const min = 60_000Autoscale limits
Pass a pair of numbers as value for a range with a low and a high end, and names to label each end.
tsx
import { state } from '@kerf-js/core'import { Row, Slider, Stack, Text } from '@kerf-js/veneer'export function Autoscale() { const copies = state<[number, number]>([2, 6]) return ( <Stack gap="group"> <Slider label="Keep between" value={copies.value} min={1} max={12} names={['Fewest copies', 'Most copies']} onChange={(v) => (copies.value = v)} /> <Stack gap="tight"> <Row justify="between"> <Text subtle>When quiet</Text> <Text> €{copies.value[0] * COPY_COST} a month </Text> </Row> <Row justify="between"> <Text subtle>At full load</Text> <Text> €{copies.value[1] * COPY_COST} a month </Text> </Row> </Stack> </Stack> )}const min = 60_000const COPY_COST = 42When to use
Use it for
- A value in a known range where the feel matters more than the digit
Reach for something else
- NumberField, when people need an exact number
- Segmented, when there are only a few fixed steps
Accessibility
- ←→
- One step down or up
- PageUpPageDown
- A bigger step
- HomeEnd
- The minimum or maximum
- Each thumb has the
sliderrole and is named by the label. - People who can't drag can tap the track or use the keys.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Its accessible name. Fields show it; icon-only controls speak it. |
value | V | — | One number, or two for a range. |
min | number | 0 | The lowest allowed value. |
max | number | 100 | The highest allowed value. |
step | number | 1 | How far one key press moves it. |
format | ((v: number) => string) | String | Turns the number into the text shown and read out. |
names | [string, string] | — | What each thumb of a range means, for screen readers. |
disabled | boolean | false | Turns it off, and takes it out of the tab order. |
name | string | — | Posts with a form: one entry per thumb. |
| Event | Type | Default | Description |
|---|---|---|---|
onChange | (value: V) => void | — | Called with the new number or pair. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="range-head"] [data-part="track"]
trackrangethumb
RelatedNumber fieldSegmented