Slider
A Base UI Slider for approximate values where relative position matters: an outlined track, an ink indicator and a tall thumb, with the value always shown in text.
import { Slider } from '@fairgarden-private/design/components/Slider'
The label and value sit above a full-width track; formatValue adds a unit or a derived rate ("1M (≈24 WPM)"). Arrow keys step, Page Up and Page Down step by ten, Home and End jump to the ends. Never make a slider the only way to enter a precise value; exact values belong in a Number Field.
States
States
Hover gives the thumb a soft --primary3 face; dragging steps its edge to 3 px, and a drag chip in the overlay face shows the value above the thumb. stepped adds the tick scale: 12 px major ticks with labels (marks, by default the ends and midpoint) and 6 px minor ticks at each step; labels thin to the ends and midpoint below 768 px and to the ends below 360 px. A range passes an array value and names each thumb with thumbLabels. Disabled draws dotted track and thumb edges and removes the indicator, but the value stays.
'use client'
import * as React from 'react'
import { Slider } from '@fairgarden-private/design/components/Slider'
import styles from './states.module.css'
/**
* Continuous with a unit, stepped with a labelled tick scale, a two-thumb
* range, and disabled (the indicator goes, the value stays).
*/
export function SliderStates() {
return (
<div className={styles.stack}>
<Slider
label="Walking Distance"
defaultValue={6}
max={20}
step={0.5}
formatValue={(formatted) => `${formatted[0]} km`}
/>
<Slider
label="Group Size"
stepped
defaultValue={8}
min={0}
max={20}
marks={[
{ value: 0 },
{ value: 5 },
{ value: 10 },
{ value: 15 },
{ value: 20 },
]}
/>
<Slider
label="Price Range"
defaultValue={[40, 120]}
max={200}
step={5}
minStepsBetweenValues={2}
format={{ style: 'currency', currency: 'USD', maximumFractionDigits: 0 }}
thumbLabels={['Minimum price', 'Maximum price']}
/>
<Slider label="Elevation Gain" defaultValue={300} max={1000} disabled formatValue={(formatted) => `${formatted[0]} m`} />
</div>
)
}
Primary scale
Primary scale
primary drives every part: the track edge, indicator, thumb edge, ticks and value. secondary is unused.
import { Slider } from '@fairgarden-private/design/components/Slider'
import styles from './color.module.css'
/** `primary` drives every part; `secondary` is unused, since the indicator is structure, not a selection. */
export function SliderColor() {
return (
<div className={styles.grid}>
<Slider label="Scope Colors" defaultValue={40} />
<Slider label="Primary Plum" primary="plum" defaultValue={60} />
<Slider label="Primary Indigo" primary="indigo" defaultValue={80} />
</div>
)
}
On grounds
On paper and forest
The thumb face is --role-halo, the scope's step 1 on every ground and in both modes, ringed by its --primary12 edge. In print the control is hidden and the slider prints as "Label: value".
'use client'
import { Slider } from '@fairgarden-private/design/components/Slider'
import { PresetGround } from '@/components/PresetGround'
import styles from './grounds.module.css'
const presets = ['paper', 'forest'] as const
/** The same roles on two grounds; the thumb face is --role-halo, the scope's step 1, everywhere. */
export function SliderGrounds() {
return (
<div className={styles.row}>
{presets.map((preset) => (
<PresetGround key={preset} preset={preset} className={styles.face}>
<span className={styles.name}>{preset}</span>
<Slider label="Shade Cover" defaultValue={45} formatValue={(formatted) => `${formatted[0]}%`} />
<Slider label="Trail Grade" stepped defaultValue={3} max={10} />
</PresetGround>
))}
</div>
)
}
API Reference
A Base UI Slider for approximate values where relative position
matters: an outlined track, a --primary12 indicator and a tall
--role-halo thumb, with the value always shown in text. Exact values use
a Number Field. A range passes an array value / defaultValue.
| Prop | Type | Description |
|---|---|---|
label | | The field label, above the track; title case up to about four words [D160]. |
formatValue | | Formats the value readout at the right end of the label row, e.g. a unit or a derived rate in parentheses (“1M (≈24 WPM)"). Default: the formatted values joined by “ — “. |
marks | |
|
minorStep | |
|
primary | | Primary Radix scale: every part (track edge, indicator, thumb edge, ticks, value). Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: unused by the slider itself. Never defaulted. |
stepped | | Shows the tick scale under the track: minor and major ticks, major labels. Default |
thumbLabels | | Accessible names per thumb, needed for a range (“Minimum price”, “Maximum price”). |
Additional types
SliderMark
A major tick on a stepped slider: its value and optional label.
type SliderMark = {
/** The value the tick marks, between `min` and `max`. */
value: number;
/** The label under the tick; defaults to the formatted value. */
label?: React.ReactNode;
}SliderProps
Props for Slider: Base UI Slider.Root props plus the stepped and color axes, the label, the value readout and the tick scale.
type SliderProps<Value extends number | number[] = number | number[]> = {
/** Shows the tick scale under the track: minor and major ticks, major labels. Default `false`. */
stepped?: boolean | null;
/**
* Primary Radix scale: every part (track edge, indicator, thumb edge,
* ticks, value). Never defaulted; omitted, it inherits the scope [D133].
*/
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
/** Secondary Radix scale: unused by the slider itself. Never defaulted. */
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
/** The field label, above the track; title case up to about four words [D160]. */
label?: React.ReactNode;
/**
* Formats the value readout at the right end of the label row, e.g. a
* unit or a derived rate in parentheses ("1M (≈24 WPM)"). Default: the
* formatted values joined by " – ".
*/
formatValue?: (formattedValues: string[], values: number[]) => React.ReactNode;
/** `stepped` only: the major ticks. Default: `min`, the midpoint and `max`. */
marks?: SliderMark[];
/** `stepped` only: the minor tick spacing. Default `step`. */
minorStep?: number;
/** Accessible names per thumb, needed for a range ("Minimum price", "Maximum price"). */
thumbLabels?: string[];
}Specification: DESIGN-SYSTEM.md §10.10 (slider).