Slider
View as MarkdownAn input for selecting a value, or a range of values, from a given range.
<ui:slider.root defaultValue="30">
<div class="flex justify-between">
<ui:slider.label>Volume</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
</ui:slider.root>
import { mountAll } from 'fluid-primitives';
import { Slider } from 'fluid-primitives/slider';
mountAll('ui:slider', ({ props }) => {
const slider = new Slider(props);
slider.init();
return slider;
});
Features
Permalink to heading "Features"- Full keyboard navigation support with arrow, page and home/end keys
- Supports touch, mouse and pointer interactions, including clicking the track
- Supports a range of values with multiple thumbs, with a configurable minimum gap between them
- Supports custom step,
largeStepand min/max values - Supports marks/ticks along the track
- Accepts
defaultValueas a single number for one thumb, or a list of numbers for a range - Works with the Field component for form integration
Installation
Permalink to heading "Installation"typo3 ui:add slider
Please copy the files manually from GitHub into your project.
Read more about installing Components and Primitives.
Examples
Permalink to heading "Examples"Use two thumbs to let users pick a range of values.
<ui:slider.root defaultValue="{0: 25, 1: 75}" minStepsBetweenThumbs="10">
<div class="flex justify-between">
<ui:slider.label>Price range</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb index="0" />
<ui:slider.thumb index="1" />
</ui:slider.control>
</ui:slider.root>
With marks
Permalink to heading "With marks"Render slider.marker elements to show ticks - with a label - along the track.
<ui:slider.root defaultValue="{0: 40}">
<div class="flex justify-between">
<ui:slider.label>Zoom level</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
<ui:slider.markerGroup>
<ui:slider.marker value="0">0%</ui:slider.marker>
<ui:slider.marker value="25">25%</ui:slider.marker>
<ui:slider.marker value="50">50%</ui:slider.marker>
<ui:slider.marker value="75">75%</ui:slider.marker>
<ui:slider.marker value="100">100%</ui:slider.marker>
</ui:slider.markerGroup>
</ui:slider.root>
Disabled
Permalink to heading "Disabled"Prevent the slider from being interacted with.
<ui:slider.root defaultValue="{0: 50}" disabled="{true}">
<div class="flex justify-between">
<ui:slider.label>Brightness</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
</ui:slider.root>
With a number input
Permalink to heading "With a number input"Pair the slider with a number-input for precise entry, keeping both in sync by updating one
whenever the other changes. Both are mounted as independent, hydration-controlled instances
(controlled="{true}" + a fixed rootId) so a custom entry file can wire them together, the same
pattern Combobox's custom filter example uses. Both
components' own onValueChange call into one shared setValue() function instead of writing to
each other directly, so there's a single guard - skip if it's already the current value - rather
than a syncing flag guessing which call is the "real" one.
<f:variable name="defaultValue" value="50" />
<div class="flex flex-col items-center gap-4">
<ui:slider.root rootId="synced-slider" controlled="{true}" defaultValue="{defaultValue}" class="max-w-55">
<ui:slider.label>Discount</ui:slider.label>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
</ui:slider.root>
<ui:numberInput.root rootId="synced-number-input" controlled="{true}" defaultValue="{defaultValue}" min="0" max="100" class="shrink-0">
<ui:numberInput.control>
<ui:numberInput.decrementTrigger />
<ui:numberInput.input />
<ui:numberInput.incrementTrigger />
</ui:numberInput.control>
</ui:numberInput.root>
</div>
<vite:asset entry="EXT:docs/Resources/Private/Components/ui/Slider/Examples/WithNumberInput.entry.ts" />
import { getHydrationData } from 'fluid-primitives';
import { NumberInput } from 'fluid-primitives/number-input';
import { Slider } from 'fluid-primitives/slider';
(() => {
const sliderData = getHydrationData('ui:slider', 'synced-slider');
const numberInputData = getHydrationData('ui:numberInput', 'synced-number-input');
if (!sliderData || !numberInputData) {
console.error('Missing hydration data for slider + number input sync example');
return;
}
let currentValue = numberInputData.props.defaultValue;
function setValue(next: number) {
if (next === currentValue) return;
currentValue = next;
slider.api.setValue([next]);
numberInput.api.setValue(next);
}
const slider = new Slider({
...sliderData.props,
onValueChange: ({ value }) => setValue(value[0]),
});
const numberInput = new NumberInput({
...numberInputData.props,
onValueChange: ({ valueAsNumber }) => {
if (!Number.isNaN(valueAsNumber)) setValue(valueAsNumber);
},
});
slider.init();
numberInput.init();
})();
With a Field
Permalink to heading "With a Field"Wrap the slider in ui:field.root to get label association and
name/disabled/invalid state propagated to the thumb automatically - a donation amount picker,
with marks for common preset amounts.
<ui:field.root name="donationAmount" class="max-w-xs">
<ui:slider.root defaultValue="25" min="0" max="200" step="5">
<div class="flex items-center justify-between">
<ui:slider.label>Donation amount</ui:slider.label>
<span class="text-sm text-muted-foreground">
$
<ui:slider.valueText />
</span>
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
<ui:slider.markerGroup>
<ui:slider.marker value="10">$10</ui:slider.marker>
<ui:slider.marker value="25">$25</ui:slider.marker>
<ui:slider.marker value="50">$50</ui:slider.marker>
<ui:slider.marker value="100">$100</ui:slider.marker>
</ui:slider.markerGroup>
</ui:slider.root>
<ui:field.description>Choose an amount to support this event - every contribution helps.</ui:field.description>
</ui:field.root>
With a dragging indicator
Permalink to heading "With a dragging indicator"Nest slider.draggingIndicator inside a slider.thumb to show its current value in a small
tooltip while it's being dragged - it's hidden the rest of the time.
<ui:slider.root defaultValue="{0: 50}">
<div class="flex justify-between">
<ui:slider.label>Progress</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb>
<ui:slider.draggingIndicator />
</ui:slider.thumb>
</ui:slider.control>
</ui:slider.root>
With decimal values
Permalink to heading "With decimal values"Set step to a fraction (e.g. 0.01) to get fine-grained, decimal precision instead of whole
numbers - useful whenever the value represents something more precise than an integer count.
<ui:slider.root defaultValue="7.98" min="5" max="10" step="0.01">
<div class="flex justify-between">
<ui:slider.label>Precision level</ui:slider.label>
<ui:slider.valueText />
</div>
<ui:slider.control>
<ui:slider.track>
<ui:slider.range />
</ui:slider.track>
<ui:slider.thumb />
</ui:slider.control>
</ui:slider.root>
API Reference
Permalink to heading "API Reference"The following tables cover the available props of the Fluid Primitives. For a full list of available client side props and methods, see the Zag.js Machine API.
slider.root
Contains every part of the slider. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
disabled | booleanWhether the slider is disabled. | No | - |
readOnly | booleanWhether the slider is read-only. | No | - |
invalid | booleanWhether the slider is invalid. | No | - |
name | stringThe name associated with each slider thumb (when used in a form). | No | - |
form | stringThe associate form of the underlying hidden input elements. | No | - |
defaultValue | float|integer|arrayThe initial value of the slider when rendered - a single number for one thumb, or a list of numbers (one per thumb) for a range. Use when you don't need to control the value of the slider. | No | - |
min | floatThe minimum value of the slider. | No | 0 |
max | floatThe maximum value of the slider. | No | 100 |
step | floatThe step value of the slider. | No | 1 |
largeStep | floatThe step value of the slider when the `Shift` key is held, or the `PageUp`/`PageDown` keys are used. Defaults to `10 * step`. | No | - |
minStepsBetweenThumbs | floatThe minimum permitted steps between multiple thumbs. `minStepsBetweenThumbs * step` reflects the gap between the thumbs. | No | 0 |
orientation | Enum\OrientationThe orientation of the slider. | No | Horizontal |
origin | Enum\SliderOriginThe origin of the slider range. The track is filled from the origin to the thumb for single values. `start` is useful when the value represents an absolute value, `center` when it represents an offset (relative), and `end` when it represents an offset from the end. | No | Start |
thumbAlignment | Enum\SliderThumbAlignmentThe alignment of the slider thumb relative to the track. `center` lets the thumb extend beyond the bounds of the track, `contain` keeps it within the track's bounds. | No | Contain |
thumbSize | arrayThe slider thumb dimensions, with a `width` and `height` key. | No | - |
thumbCollisionBehavior | Enum\SliderThumbCollisionBehaviorControls how thumbs behave when they collide during pointer interactions. `none` keeps thumbs from moving past each other, `push` makes them push each other, `swap` makes them swap places. | No | None |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
rootId | stringThe root ID of the component, used for hydration and identification. | No | - |
ids | arrayThe IDs of of the component parts for composition. | No | [] |
controlled | booleanIf true, the component is meant to be initialized manually inside another component | No | false |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | root |
data-disabled | Present when disabled |
data-orientation | The orientation of the slider |
data-dragging | Present when in the dragging state |
data-invalid | Present when invalid |
data-focus | Present when focused |
slider.label
Renders an accessible label for the slider. Renders a <label> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | label |
data-disabled | Present when disabled |
data-orientation | The orientation of the label |
data-invalid | Present when invalid |
data-dragging | Present when in the dragging state |
data-focus | Present when focused |
slider.valueText
Displays a textual representation of the current value. Renders a <span> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | value-text |
data-disabled | Present when disabled |
data-orientation | The orientation of the valuetext |
data-invalid | Present when invalid |
data-focus | Present when focused |
slider.control
Wraps the track and thumbs, and handles pointer interaction with the track. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | control |
data-dragging | Present when in the dragging state |
data-disabled | Present when disabled |
data-orientation | The orientation of the control |
data-invalid | Present when invalid |
data-focus | Present when focused |
slider.track
Renders the full length of the slider's track. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | track |
data-disabled | Present when disabled |
data-invalid | Present when invalid |
data-dragging | Present when in the dragging state |
data-orientation | The orientation of the track |
data-focus | Present when focused |
slider.range
Renders the filled portion of the track between the origin and the thumb(s). Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | range |
data-dragging | Present when in the dragging state |
data-focus | Present when focused |
data-invalid | Present when invalid |
data-disabled | Present when disabled |
data-orientation | The orientation of the range |
slider.thumb
Renders a draggable handle for one value. Takes an index prop to identify which value it controls. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
index | integerThe index of the thumb. Use a distinct index per `slider.thumb` for a range slider with multiple thumbs. | No | 0 |
name | stringThe name of the thumb. Defaults to the root `name`. | No | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | thumb |
data-index | The index of the item |
data-name | |
data-disabled | Present when disabled |
data-orientation | The orientation of the thumb |
data-focus | Present when focused |
data-dragging | Present when in the dragging state |
slider.hiddenInput
Provides a native input for form submission, nested inside a slider.thumb. Renders an <input> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
slider.markerGroup
Groups the marks/ticks rendered along the track. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | marker-group |
data-orientation | The orientation of the markergroup |
slider.marker
Renders a single mark/tick at a given value. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
value | floatThe value along the track at which to render the marker. | Yes | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | marker |
data-orientation | The orientation of the marker |
data-value | The value of the item |
data-disabled | Present when disabled |
data-state |
slider.draggingIndicator
Displays the current value while its thumb is being dragged. Nested inside a slider.thumb, whose index it follows automatically. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | slider |
data-part | dragging-indicator |
data-orientation | The orientation of the draggingindicator |
data-state | "open" | "closed" |
Machine JavaScript API
| Name | Type | Description |
|---|---|---|
value | number[] | The value of the slider. |
dragging | boolean | Whether the slider is being dragged. |
focused | boolean | Whether the slider is focused. |
setValue | (value: number[]) => void | Function to set the value of the slider. |
getThumbValue | (index: number) => number | Returns the value of the thumb at the given index. |
setThumbValue | (index: number, value: number) => void | Sets the value of the thumb at the given index. |
getValuePercent | (value: number) => number | Returns the percent of the thumb at the given index. |
getPercentValue | (percent: number) => number | Returns the value of the thumb at the given percent. |
getThumbPercent | (index: number) => number | Returns the percent of the thumb at the given index. |
setThumbPercent | (index: number, percent: number) => void | Sets the percent of the thumb at the given index. |
getThumbMin | (index: number) => number | Returns the min value of the thumb at the given index. |
getThumbMax | (index: number) => number | Returns the max value of the thumb at the given index. |
increment | (index: number) => void | Function to increment the value of the slider at the given index. |
decrement | (index: number) => void | Function to decrement the value of the slider at the given index. |
focus | VoidFunction | Function to focus the slider. This focuses the first thumb. |
Accessibility
| Key | Description |
|---|---|
ArrowRight | Increments the slider based on defined step |
ArrowLeft | Decrements the slider based on defined step |
ArrowUp | Increases the value by the step amount. |
ArrowDown | Decreases the value by the step amount. |
PageUp | Increases the value by the largeStep amount. |
PageDown | Decreases the value by the largeStep amount. |
Shift + ArrowUp | Increases the value by the largeStep amount. |
Shift + ArrowDown | Decreases the value by the largeStep amount. |
Home | Sets the value to its minimum. |
End | Sets the value to its maximum. |
<primitives:slider.root>
<primitives:slider.label />
<primitives:slider.valueText />
<primitives:slider.control>
<primitives:slider.track>
<primitives:slider.range />
</primitives:slider.track>
<primitives:slider.thumb index="0">
<primitives:slider.hiddenInput />
</primitives:slider.thumb>
<primitives:slider.markerGroup>
<primitives:slider.marker value="25" />
</primitives:slider.markerGroup>
</primitives:slider.control>
</primitives:slider.root>