Slider
A Slider lets users select a numeric value from a defined range by dragging a circle along a track.
Code example
import { Slider } from '@yleisradio/yds-components-react';
<Slider label="Label" min={0} max={100} defaultValue={40} />
Why to use
Slider makes it easy to pick a numeric value from a bounded range without typing. It's fast to adjust, which makes it especially well suited to touch and mobile contexts. It's also great for quick adjustments where the change can be seen continuously and immediately.
When to use
Use Slider when users need to pick a value within a defined numeric range and the relative position (low, mid, high) communicates meaning — for example, a price ceiling, age range, rating, or a filter threshold.
- Use Slider for bounded numeric ranges where approximate selection is acceptable and the range has a clear low-to-high direction.
- Use Slider when the interaction should be fast and easy, for example on touch and mobile surfaces, where dragging is easier than typing into a small field.
- Use Slider for quick, low-stakes adjustments where users want to see the effect of the change immediately (volume, brightness, filter thresholds).
- Use Slider with the
highlightvariant to draw attention to the slider in key user interactions (e.g. filter panels, calculators, infographic controls).
- Don't use Slider when the user must enter a value that doesn't map to a continuous range — use TextInput or Select instead.
- Don't use Slider for large discrete sets (e.g. selecting 1 of 50 named categories) — use a Select or ComboboxSingleSelect.
- Don't use Slider when the exact value is critical and an approximate selection creates errors (e.g. a date of birth) — use a TextInput.
- Don't use Slider for star ratings or other expressive scoring — use a RadioGroupNumericScale or a dedicated rating control.
- Don't use Slider when there are fewer than five steps to choose from — the thumb is hard to land precisely on a coarse scale; use Radio buttons or a Select instead.
- Don't use Slider for media playback – use dedicated media player controls instead.
Content Guidelines
- Use a short, descriptive
label(e.g. "Maximum price", "Volume"). - Use
unitto add a unit suffix to the value box (e.g. "€", "%", "vuotta"). Remember to take singular/plural into account when the unit is a word. - Use
descriptionsparinglyfor a short explanatory sentence when the range limits alone are not self-evident.
- Don't repeat the label in the description.
- Don't use errorMessage for per-keystroke validation or for range overflows that are automatically corrected when user finishes typing.
Anatomy
- Label – Describes the purpose of the range. Always visible (or visually hidden for screen readers via
labelOptions). - Value box – A compact editable TextInput that displays and accepts numeric input. Enabled by default; hide with
showValueBox={false}. - Track – The background bar representing the full range.
- Fill – The coloured segment from
minto the current value, using the variant colour. - Thumb – The circular drag handle positioned at the current value.
- Min / Max labels – Small text labels at the left and right ends of the track. Default to the numeric
min/maxvalues; customise withminLabel/maxLabel. - Description – Optional helper text below the min/max row.
- Error message – Optional message for externally-driven validation (e.g. a server response or a no-results condition). Set via
errorMessage.
Key Props
value / defaultValue / onChange
The Slider supports both controlled and uncontrolled usage.
| Pattern | Example | Notes |
|---|---|---|
| Controlled | <Slider value={val} onChange={setVal} /> | You manage state; onChange receives the new number. |
| Uncontrolled | <Slider defaultValue={40} /> | Internal state; use onChange to observe changes. |
Code example
// Controlled
const [price, setPrice] = useState(40000);
<Slider label="Maximum price" value={price} onChange={setPrice} min={0} max={100000} />
// Uncontrolled
<Slider label="Volume" defaultValue={50} />
min / max / step
Define the range and granularity of valid values.
| Prop | Type | Default | Description |
|---|---|---|---|
min | number | 0 | Minimum selectable value. |
max | number | 100 | Maximum selectable value. |
step | number | 1 | Snapping interval. Value box entry is clamped and snapped to step on blur (snapping can be disabled with snapToStep={false}). |
Code example
<Slider label="Price" min={8000} max={80000} step={1000} defaultValue={40000} />
variant
Controls the colour of the fill and thumb.
| Value | Example | Description |
|---|---|---|
default | 0100 | Suitable for forms and situations where you don't want to emphasize the slider control. |
highlight | 0100 | Suitable for situations where you want to emphasize or draw attention to the slider control. |
Code example
<Slider
label="Default"
min={0}
max={100}
defaultValue={40}
variant="default"
showValueBox={false}
/>
<Slider
label="Highlight"
min={0}
max={100}
defaultValue={40}
variant="highlight"
showValueBox={false}
/>
minLabel / maxLabel
Override the text shown at each end of the track.
| Type | Example | Description |
|---|---|---|
ReactNode | 0 €100 € | Any React content; defaults to the number-formatted min / max, with unit appended when set. |
Code example
<Slider
label="Price"
min={0}
max={100}
defaultValue={50}
minLabel="0 €"
maxLabel="100 €"
showValueBox={false}
/>
showMinMaxLabels
Controls visibility of the min/max labels at the ends of the track. Use it for compact contexts where the boundaries are already clear (e.g. when the value box and a description convey the range).
| Type | Default | Description |
|---|---|---|
boolean | true | Set to false to hide both the min and max labels. |
Code example
<Slider label="Volume" defaultValue={50} showMinMaxLabels={false} />
description
Helper text displayed below the min/max labels.
| Type | Example | Description |
|---|---|---|
string | 0100 Affects all audio output. | Short guidance for the user. |
Code example
<Slider
label="Volume"
min={0}
max={100}
defaultValue={50}
description="Affects all audio output."
showValueBox={false}
/>
errorMessage
For surfacing externally-driven feedback about the overall result of the selection — for example when the chosen value produces no results or an invalid calculation — rather than validation of the value itself. The Slider never produces an invalid value: out-of-range or non-numeric value-box input is silently corrected on blur. Because the message reflects the overall outcome rather than a momentary invalid keystroke, it is announced with aria-live="polite", so it waits for a natural pause instead of interrupting the user.
| Type | Example | Description |
|---|---|---|
string | 0100 No results match this price range. | Renders the message below the slider, announced politely (aria-live="polite"). |
Code example
<Slider
label="Maximum price"
min={0}
max={100}
defaultValue={50}
errorMessage="No results match this price range."
showValueBox={false}
/>
showValueBox
Controls visibility of the editable TextInput value box in the top-right corner.
| Type | Default | Description |
|---|---|---|
boolean | true | Set to false to hide the value box. |
Code example
<Slider label="Volume" defaultValue={50} showValueBox={false} />
unit
Appends a unit suffix inside the value box (e.g. €, %, vuotta). The box grows to fit varying-length units while the value stays right-aligned. When set, the unit is also appended to the default minLabel / maxLabel (e.g. 0 € / 80 000 €) unless you override them.
| Type | Example | Description |
|---|---|---|
string | vuotta | Unit shown after the value in the box. |
Code example
<Slider label="Loan period" min={1} max={30} defaultValue={15} unit="vuotta" />
<Slider label="Maximum price" min={8000} max={80000} step={1000} defaultValue={43000} unit="€" />
numberFormat
Controls how the value is displayed in and parsed from the value box, min/max labels, and the screen-reader aria-valuetext. Defaults to Finnish (fi-FI) conventions — a no-break space groups thousands and a comma is the decimal delimiter — so you rarely need to set it. Override individual fields when needed; pass thousandSeparator: '' to disable grouping.
| Field | Type | Default | Description |
|---|---|---|---|
thousandSeparator | string | '\u00a0' (no-break space) | Character between groups of three digits. |
decimalDelimiter | string | ',' | Decimal delimiter. |
decimalPlaces | number | precision of step | Number of decimal places to display. |
Code example
// fi-FI by default → "43 000"
<Slider label="Maximum price" min={8000} max={80000} step={1000} defaultValue={43000} unit="€" />
// Interest rate with two decimals → "3,50"
<Slider
label="Interest rate"
min={0}
max={10}
step={0.01}
defaultValue={3.5}
unit="%"
numberFormat={{ decimalPlaces: 2 }}
/>
// Disable grouping → "43000"
<Slider label="Code" min={0} max={99999} defaultValue={43000} numberFormat={{ thousandSeparator: '' }} />
inputMode
Sets the virtual-keyboard hint for the value box. Defaults to 'decimal' when fractional values are allowed (via step or numberFormat.decimalPlaces), otherwise 'numeric'. Override it when the automatic choice isn't appropriate.
| Type | Default | Description |
|---|---|---|
'numeric' | 'decimal' | 'text' | 'none' | auto | Forwarded to the value box <input>'s inputMode. |
Code example
<Slider label="Amount" min={0} max={100} step={0.5} defaultValue={10} inputMode="decimal" />
snapToStep
Controls whether the value box snaps entries to step. Defaults to true. When false, the box accepts any number within [min, max] (a typed value like 43 521 is kept as-is and the thumb sits exactly on it), while dragging the slider still snaps to step. The range temporarily uses step="any" after a value is typed so the thumb can rest on the exact value, and the prop step is restored the moment the slider is engaged.
| Type | Default | Description |
|---|---|---|
boolean | true | Set to false to allow exact, off-step values via the value box while keeping a stepped slider. |
Code example
<Slider
label="Maximum price"
min={8000}
max={80000}
step={1000}
defaultValue={43000}
unit="€"
snapToStep={false}
/>
isDisabled
Prevents user interaction with both the range input and the value box.
| Type | Example | Description |
|---|---|---|
boolean | 0100 | Disables the control. |
Code example
<Slider label="Disabled" min={0} max={100} defaultValue={50} isDisabled showValueBox={false} />
Behavior
- Dragging the thumb or pressing arrow keys on the focused range input updates the value immediately and calls
onChange. - The value box reflects the current value at all times. Editing the box updates the range on blur or when
Enteris pressed. - Numbers are formatted with Finnish (fi-FI) conventions by default (no-break space thousands separator, comma decimal); customise via
numberFormat. - Invalid input in the value box is silently corrected on blur with no error state shown: out-of-range values are clamped to
[min, max]and (unlesssnapToStep={false}) snapped to the neareststep; empty or non-numeric input reverts to the current value. - With
snapToStep={false}, the range temporarily switches tostep="any"after a value is typed so the thumb rests on the exact value, and restores the propstepthe moment the slider is engaged so dragging snaps to the grid. - In controlled mode, state is managed by the parent. In uncontrolled mode, state is managed internally.
- The
refis forwarded to the underlying<input type="range">element.
Accessibility
Things to keep in mind when using this component:
- Always pass a clear, descriptive
label. It names both the slider and its value box. Only uselabelOptions={{ isHidden: true }}when the surrounding content already makes the purpose unambiguous.
(WCAG 3.3.2 — Labels or Instructions) - When you set a
unit(e.g.€,%), choose a value that reads well aloud — it is spoken as part of the value (e.g. "43 000 euroa" depends on how the screen reader pronounces the symbol). Prefer a word unit (vuotta) when a symbol would be ambiguous. - Don't rely on the
variantcolour alone to convey meaning; the colour difference is decorative.
(WCAG 1.4.1 — Use of Color) - Use
errorMessageonly for outcome-level feedback (no results, failed calculation), not for per-keystroke validation. It is announced politely so it won't talk over the user — avoid putting time-critical or blocking information in it. - Give the range meaningful context through
min/maxlabels (or adescription) when the bare numbers aren't self-explanatory; hiding them withshowMinMaxLabels={false}is fine only when the value box and surrounding copy already convey the range. - The value box is a real text field — keep
step,numberFormat, andunitconsistent with what users are expected to type, so keyboard entry matches what they see. - There are unresolved accessibility difficulties with
input type="number", thus we useinput type="text"with a custom value box. Component tries to use the correctinputModefor the expected mobile keyboard input (e.g.decimalfor fractional values,numericfor whole numbers).
Implementation examples
Price range slider
A common use case — a budget selector with currency min/max labels and a description.
Select the maximum price for your search.
Code example
import { Slider } from '@yleisradio/yds-components-react';
<Slider
label="Maximum price"
min={8000}
max={80000}
step={1000}
defaultValue={43000}
minLabel="8 000 €"
maxLabel="80 000 €"
description="Select the maximum price for your search."
variant="highlight"
/>
With external validation feedback
Use errorMessage when the parent determines the selected value is invalid — for example when a search returns no results for the chosen range.
No results match this price range.
Code example
import { Slider } from '@yleisradio/yds-components-react';
<Slider
label="Maximum price"
min={8000}
max={80000}
step={1000}
defaultValue={79000}
minLabel="8 000 €"
maxLabel="80 000 €"
variant="highlight"
errorMessage="No results match this price range."
/>
API Reference
Props
The Slider component forwards additional props to the underlying <input type="range"> element. Note that onChange, value, and defaultValue are replaced by the Slider-specific versions below.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | Yes | — | Visible label for the field. |
labelOptions | FormElementLabelProps | No | {} | Options forwarded to FormElementLabel (e.g. isHidden, optionalLabel). |
id | string | No | auto-generated | HTML id for the range input. Used to wire label and ARIA attributes. |
value | number | No | — | Controlled value. |
defaultValue | number | No | min | Uncontrolled initial value. |
onChange | (value: number) => void | No | — | Called with the new numeric value on every change. |
min | number | No | 0 | Minimum value. |
max | number | No | 100 | Maximum value. |
step | number | No | 1 | Step interval. Box entry snaps to it unless snapToStep={false}. |
variant | SliderVariant | No | 'default' | 'default' or 'highlight'. |
description | string | No | — | Helper text shown below min/max labels. |
errorMessage | string | No | — | External outcome feedback (e.g. no results or failed calculation), announced via aria-live="polite". |
minLabel | ReactNode | No | formatted min (+ unit) | Content shown at the left end of the track. Defaults to the number-formatted min, with unit appended when set. |
maxLabel | ReactNode | No | formatted max (+ unit) | Content shown at the right end of the track. Defaults to the number-formatted max, with unit appended when set. |
showMinMaxLabels | boolean | No | true | Show/hide the min and max track labels. |
showValueBox | boolean | No | true | Show/hide the editable value box. |
valueBoxLabel | string | No | label | Accessible label for the value box (visually hidden). |
unit | string | No | — | Unit suffix shown inside the value box (e.g. €, %, vuotta). |
numberFormat | SliderNumberFormat | No | fi-FI | Thousand separator, decimal delimiter and decimal places for display/parse. Defaults to Finnish (fi-FI) conventions: a no-break space groups thousands and a comma is the decimal delimiter. |
inputMode | 'numeric' | 'decimal' | 'text' | 'none' | No | auto | Virtual-keyboard hint for the value box. Defaults to decimal when fractional values are allowed, otherwise numeric. |
snapToStep | boolean | No | true | When false, the value box accepts any number within [min, max] (no rounding to step) and the thumb sits exactly on it; dragging the slider still snaps to step. |
isDisabled | boolean | No | false | Disables the slider and value box. |
isRequired | boolean | No | false | Marks the field as required. |
Type Definitions
export type SliderVariant = 'default' | 'highlight';
export interface SliderDSProps {
label: string;
labelOptions?: FormElementLabelProps;
id?: string;
value?: number;
defaultValue?: number;
onChange?: (value: number) => void;
min?: number;
max?: number;
step?: number;
variant?: SliderVariant;
description?: string;
errorMessage?: string;
minLabel?: ReactNode;
maxLabel?: ReactNode;
showMinMaxLabels?: boolean;
showValueBox?: boolean;
valueBoxLabel?: string;
unit?: string;
numberFormat?: SliderNumberFormat;
inputMode?: 'numeric' | 'decimal' | 'text' | 'none';
snapToStep?: boolean;
isDisabled?: boolean;
isRequired?: boolean;
}
export interface SliderNumberFormat {
/** Character inserted between groups of three digits. Defaults to a no-break space ('\u00a0'), per Finnish (fi-FI) convention. Pass '' to disable grouping. */
thousandSeparator?: string;
/** Character used as the decimal delimiter. Defaults to ',', per Finnish (fi-FI) convention. */
decimalDelimiter?: string;
/** Number of decimal places to display. Defaults to the precision implied by `step`. */
decimalPlaces?: number;
}
export type SliderProps = Omit<
InputHTMLAttributes<HTMLInputElement>,
'onChange' | 'value' | 'defaultValue'
> &
SliderDSProps;
Related Components
- ProgressBar: For displaying read-only progress or completion, not for user input.
- TextInput: For free-form numeric entry without a range constraint.
- Select: For choosing from a fixed set of discrete values.