Data input
Slider
A native range input on a styled track, with one thumb for a value or two for a range.
| Class name | Type | Description |
|---|---|---|
rangeplf:range | Component | A native range input |
range-fieldplf:range-field | Part | Holds the range inputs on one track |
range-outputplf:range-output | Part | Shows a value |
Default
The script snaps values to step and shows each <output>, authored hidden, with the value of the range input its for names; units such as % stay in your markup.
Minimum 0; maximum 100; step 1.
<div data-plf-slider>
<div class="flex flex-wrap items-center gap-4 justify-between">
<label class="field-label" for="slider-default">Volume</label>
<span class="field-help">
<output class="range-output" for="slider-default" hidden>60</output>%
</span>
</div>
<div class="range-field">
<input class="range" type="range" id="slider-default" name="volume" value="60" aria-describedby="slider-default-help">
</div>
</div>
<p class="field-help" id="slider-default-help">Minimum 0; maximum 100; step 1.</p><div data-plf-slider>
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<label class="plf:field-label" for="slider-default">Volume</label>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-default" hidden>60</output>%
</span>
</div>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-default" name="volume" value="60" aria-describedby="slider-default-help">
</div>
</div>
<p class="plf:field-help" id="slider-default-help">Minimum 0; maximum 100; step 1.</p>import { Slider } from '@pelatform/react';
export function Example() {
return <Slider label="Volume" name="volume" defaultValue={60} help="Minimum 0; maximum 100; step 1.">%</Slider>;
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return <Slider label="Volume" name="volume" defaultValue={60} help="Minimum 0; maximum 100; step 1.">%</Slider>;
}Step
A decimal step works like a whole number; step="any" is not supported.
Minimum 0; maximum 1; step 0.05.
<div data-plf-slider>
<div class="flex flex-wrap items-center gap-4 justify-between">
<label class="field-label" for="slider-step">Opacity</label>
<span class="field-help">
<output class="range-output" for="slider-step" hidden>0.65</output>
</span>
</div>
<div class="range-field">
<input class="range" type="range" id="slider-step" name="opacity" min="0" max="1" step="0.05" value="0.65" aria-describedby="slider-step-help">
</div>
</div>
<p class="field-help" id="slider-step-help">Minimum 0; maximum 1; step 0.05.</p><div data-plf-slider>
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<label class="plf:field-label" for="slider-step">Opacity</label>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-step" hidden>0.65</output>
</span>
</div>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-step" name="opacity" min="0" max="1" step="0.05" value="0.65" aria-describedby="slider-step-help">
</div>
</div>
<p class="plf:field-help" id="slider-step-help">Minimum 0; maximum 1; step 0.05.</p>import { Slider } from '@pelatform/react';
export function Example() {
return (
<Slider
label="Opacity"
name="opacity"
min={0}
max={1}
step={0.05}
defaultValue={0.65}
help="Minimum 0; maximum 1; step 0.05."
/>
);
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return (
<Slider
label="Opacity"
name="opacity"
min={0}
max={1}
step={0.05}
defaultValue={0.65}
help="Minimum 0; maximum 1; step 0.05."
/>
);
}Range
Give both inputs the same min, max and step, the lower value first.
Minimum -1; maximum 1; step 0.1.
<div data-plf-slider role="group" aria-labelledby="slider-temperature-label">
<div class="flex flex-wrap items-center gap-4 justify-between">
<span class="field-label" id="slider-temperature-label">Temperature range</span>
<span class="field-help">
<output class="range-output" for="slider-temperature-0" hidden>-0.3</output>
<span aria-hidden="true">–</span>
<output class="range-output" for="slider-temperature-1" hidden>0.7</output>
</span>
</div>
<label class="sr-only" for="slider-temperature-0">Temperature range minimum</label>
<label class="sr-only" for="slider-temperature-1">Temperature range maximum</label>
<div class="range-field">
<input class="range" type="range" id="slider-temperature-0" name="temperature-min" min="-1" max="1" step="0.1" value="-0.3" aria-describedby="slider-temperature-help">
<input class="range" type="range" id="slider-temperature-1" name="temperature-max" min="-1" max="1" step="0.1" value="0.7" aria-describedby="slider-temperature-help">
</div>
</div>
<p class="field-help" id="slider-temperature-help">Minimum -1; maximum 1; step 0.1.</p><div data-plf-slider role="group" aria-labelledby="slider-temperature-label">
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<span class="plf:field-label" id="slider-temperature-label">Temperature range</span>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-temperature-0" hidden>-0.3</output>
<span aria-hidden="true">–</span>
<output class="plf:range-output" for="slider-temperature-1" hidden>0.7</output>
</span>
</div>
<label class="plf:sr-only" for="slider-temperature-0">Temperature range minimum</label>
<label class="plf:sr-only" for="slider-temperature-1">Temperature range maximum</label>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-temperature-0" name="temperature-min" min="-1" max="1" step="0.1" value="-0.3" aria-describedby="slider-temperature-help">
<input class="plf:range" type="range" id="slider-temperature-1" name="temperature-max" min="-1" max="1" step="0.1" value="0.7" aria-describedby="slider-temperature-help">
</div>
</div>
<p class="plf:field-help" id="slider-temperature-help">Minimum -1; maximum 1; step 0.1.</p>import { Slider } from '@pelatform/react';
export function Example() {
return (
<Slider
label="Temperature range"
name={['temperature-min', 'temperature-max']}
min={-1}
max={1}
step={0.1}
defaultValue={[-0.3, 0.7]}
help="Minimum -1; maximum 1; step 0.1."
/>
);
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return (
<Slider
label="Temperature range"
name={['temperature-min', 'temperature-max']}
min={-1}
max={1}
step={0.1}
defaultValue={[-0.3, 0.7]}
help="Minimum -1; maximum 1; step 0.1."
/>
);
}Exact values
A number field inside the slider follows the thumb of its order, and a typed value moves that thumb.
Both ends stay ordered.
<div data-plf-slider role="group" aria-labelledby="slider-budget-label">
<div class="flex flex-wrap items-center gap-4 justify-between">
<span class="field-label" id="slider-budget-label">Monthly budget</span>
<span class="field-help">
<output class="range-output" for="slider-budget-0" hidden>250</output>
<span aria-hidden="true">–</span>
<output class="range-output" for="slider-budget-1" hidden>1250</output>
</span>
</div>
<label class="sr-only" for="slider-budget-0">Monthly budget minimum</label>
<label class="sr-only" for="slider-budget-1">Monthly budget maximum</label>
<div class="range-field">
<input class="range" type="range" id="slider-budget-0" name="budget-min" min="0" max="2000" step="50" value="250" aria-describedby="slider-budget-help">
<input class="range" type="range" id="slider-budget-1" name="budget-max" min="0" max="2000" step="50" value="1250" aria-describedby="slider-budget-help">
</div>
<div class="grid grid-cols-2 gap-4 mt-4">
<div class="field">
<label class="field-label" for="slider-budget-number-0">Minimum</label>
<input class="input" type="number" id="slider-budget-number-0">
</div>
<div class="field">
<label class="field-label" for="slider-budget-number-1">Maximum</label>
<input class="input" type="number" id="slider-budget-number-1">
</div>
</div>
</div>
<p class="field-help" id="slider-budget-help">Both ends stay ordered.</p><div data-plf-slider role="group" aria-labelledby="slider-budget-label">
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<span class="plf:field-label" id="slider-budget-label">Monthly budget</span>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-budget-0" hidden>250</output>
<span aria-hidden="true">–</span>
<output class="plf:range-output" for="slider-budget-1" hidden>1250</output>
</span>
</div>
<label class="plf:sr-only" for="slider-budget-0">Monthly budget minimum</label>
<label class="plf:sr-only" for="slider-budget-1">Monthly budget maximum</label>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-budget-0" name="budget-min" min="0" max="2000" step="50" value="250" aria-describedby="slider-budget-help">
<input class="plf:range" type="range" id="slider-budget-1" name="budget-max" min="0" max="2000" step="50" value="1250" aria-describedby="slider-budget-help">
</div>
<div class="plf:grid plf:grid-cols-2 plf:gap-4 plf:mt-4">
<div class="plf:field">
<label class="plf:field-label" for="slider-budget-number-0">Minimum</label>
<input class="plf:input" type="number" id="slider-budget-number-0">
</div>
<div class="plf:field">
<label class="plf:field-label" for="slider-budget-number-1">Maximum</label>
<input class="plf:input" type="number" id="slider-budget-number-1">
</div>
</div>
</div>
<p class="plf:field-help" id="slider-budget-help">Both ends stay ordered.</p>import { Slider } from '@pelatform/react';
export function Example() {
return (
<Slider
label="Monthly budget"
name={['budget-min', 'budget-max']}
min={0}
max={2000}
step={50}
defaultValue={[250, 1250]}
numberLabels={['Minimum', 'Maximum']}
help="Both ends stay ordered."
/>
);
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return (
<Slider
label="Monthly budget"
name={['budget-min', 'budget-max']}
min={0}
max={2000}
step={50}
defaultValue={[250, 1250]}
numberLabels={['Minimum', 'Maximum']}
help="Both ends stay ordered."
/>
);
}Disabled
In a range, disable one input to lock that end; aria-disabled="true" looks like disabled and blocks changes, but keeps the value in the form.
This setting is unavailable.
This setting is unavailable.
<div data-plf-slider>
<div class="flex flex-wrap items-center gap-4 justify-between">
<label class="field-label" for="slider-disabled">Locked setting</label>
<span class="field-help">
<output class="range-output" for="slider-disabled" hidden>40</output>
</span>
</div>
<div class="range-field">
<input class="range" type="range" id="slider-disabled" name="locked" value="40" aria-describedby="slider-disabled-help" disabled>
</div>
</div>
<p class="field-help" id="slider-disabled-help">This setting is unavailable.</p>
<div data-plf-slider role="group" aria-labelledby="slider-disabled-range-label">
<div class="flex flex-wrap items-center gap-4 justify-between">
<span class="field-label" id="slider-disabled-range-label">Locked range</span>
<span class="field-help">
<output class="range-output" for="slider-disabled-range-0" hidden>30</output>
<span aria-hidden="true">–</span>
<output class="range-output" for="slider-disabled-range-1" hidden>70</output>
</span>
</div>
<label class="sr-only" for="slider-disabled-range-0">Locked range minimum</label>
<label class="sr-only" for="slider-disabled-range-1">Locked range maximum</label>
<div class="range-field">
<input class="range" type="range" id="slider-disabled-range-0" name="locked-min" value="30" aria-describedby="slider-disabled-range-help" disabled>
<input class="range" type="range" id="slider-disabled-range-1" name="locked-max" value="70" aria-describedby="slider-disabled-range-help" disabled>
</div>
</div>
<p class="field-help" id="slider-disabled-range-help">This setting is unavailable.</p><div data-plf-slider>
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<label class="plf:field-label" for="slider-disabled">Locked setting</label>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-disabled" hidden>40</output>
</span>
</div>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-disabled" name="locked" value="40" aria-describedby="slider-disabled-help" disabled>
</div>
</div>
<p class="plf:field-help" id="slider-disabled-help">This setting is unavailable.</p>
<div data-plf-slider role="group" aria-labelledby="slider-disabled-range-label">
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<span class="plf:field-label" id="slider-disabled-range-label">Locked range</span>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-disabled-range-0" hidden>30</output>
<span aria-hidden="true">–</span>
<output class="plf:range-output" for="slider-disabled-range-1" hidden>70</output>
</span>
</div>
<label class="plf:sr-only" for="slider-disabled-range-0">Locked range minimum</label>
<label class="plf:sr-only" for="slider-disabled-range-1">Locked range maximum</label>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-disabled-range-0" name="locked-min" value="30" aria-describedby="slider-disabled-range-help" disabled>
<input class="plf:range" type="range" id="slider-disabled-range-1" name="locked-max" value="70" aria-describedby="slider-disabled-range-help" disabled>
</div>
</div>
<p class="plf:field-help" id="slider-disabled-range-help">This setting is unavailable.</p>import { Slider } from '@pelatform/react';
export function Example() {
return (
<>
<Slider label="Locked setting" name="locked" defaultValue={40} help="This setting is unavailable." disabled />
<Slider label="Locked range" name={['locked-min', 'locked-max']} defaultValue={[30, 70]} help="This setting is unavailable." disabled />
</>
);
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return (
<>
<Slider label="Locked setting" name="locked" defaultValue={40} help="This setting is unavailable." disabled />
<Slider label="Locked range" name={['locked-min', 'locked-max']} defaultValue={[30, 70]} help="This setting is unavailable." disabled />
</>
);
}Invalid
The slider does not validate values: set aria-invalid="true" from your own checks.
Choose a value from the allowed range.
<div data-plf-slider>
<div class="flex flex-wrap items-center gap-4 justify-between">
<label class="field-label" for="slider-invalid">Outside policy</label>
<span class="field-help">
<output class="range-output" for="slider-invalid" hidden>90</output>
</span>
</div>
<div class="range-field">
<input class="range" type="range" id="slider-invalid" name="limit" value="90" aria-describedby="slider-invalid-error" aria-invalid="true">
</div>
</div>
<p class="field-error" id="slider-invalid-error">Choose a value from the allowed range.</p><div data-plf-slider>
<div class="plf:flex plf:flex-wrap plf:items-center plf:gap-4 plf:justify-between">
<label class="plf:field-label" for="slider-invalid">Outside policy</label>
<span class="plf:field-help">
<output class="plf:range-output" for="slider-invalid" hidden>90</output>
</span>
</div>
<div class="plf:range-field">
<input class="plf:range" type="range" id="slider-invalid" name="limit" value="90" aria-describedby="slider-invalid-error" aria-invalid="true">
</div>
</div>
<p class="plf:field-error" id="slider-invalid-error">Choose a value from the allowed range.</p>import { Slider } from '@pelatform/react';
export function Example() {
return <Slider label="Outside policy" name="limit" defaultValue={90} error="Choose a value from the allowed range." />;
}import { Slider } from '@pelatform/react/prefixed';
export function Example() {
return <Slider label="Outside policy" name="limit" defaultValue={90} error="Choose a value from the allowed range." />;
}JavaScript
Slider needs JavaScript. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/slider.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/slider.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/slider.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/slider.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>| Attribute | Purpose |
|---|---|
data-plf-slider |
Marks the container; the script adds data-plf-slider-enhanced |
<output for="…"> |
Optional, authored hidden: shows the value of the range input its for names; the script shows it with aria-live="off" unless you set one |
<input type="number"> |
Optional, one per thumb in the slider: follows the thumb of its order, and a typed value moves that thumb, snapped to the step. The script copies min, max and step when the field has none |
aria-valuemin, aria-valuemax |
Set by the script in a range, following the other value, so the thumbs cannot pass each other |
| Method | Behavior |
|---|---|
PLF. |
Returns the instance, creating it for valid markup; invalid markup logs an error, and the native inputs keep working |
PLF. |
Returns the instance or null |
instance. |
Returns an array of one or two values |
instance. |
Returns {values, min, max, step, disabled}, with one disabled boolean per input |
instance. |
Sets every value at once, snapped to the step; returns false when unchanged, out of order, canceled or touching a disabled input; fires no native events |
instance. |
Focuses the input at index, 0 by default |
instance. |
Removes listeners and restores the attributes and outputs it set; values stay. Destroy and initialize again to change min, max, step or the inputs |
With ESM, import Slider from @pelatform/ui/components/slider.
After setting an input’s .value in code, fire its input or change event so the slider follows.
| Event | When |
|---|---|
plf: |
Before a new value is accepted; cancelable |
plf: |
After the inputs and outputs show the new value |
Each event’s detail:
| Property | Value |
|---|---|
instance |
The Slider instance |
reason |
api, trigger for the native input or pointer for the track |
trigger |
The range input or number field, or null from a method |
previousState |
The state before the change, shaped like getState |
state |
The new state, shaped like getState |
Events bubble from the container. Initialization, reset and destroy() send no events.
Keyboard
| Key | Action |
|---|---|
| Tab, Shift+Tab | Move between thumbs, lower first, whatever their values |
| Arrow keys, Page Up, Page Down, Home, End | The browser’s own range keys; in a range they stop at the other thumb. In right-to-left layouts the scale runs from the right |
| Click or drag on the track | Moves the nearest thumb, with native input events and one change on release |
React
Slider from @pelatform/react renders this markup with its label, value and help, and moves its thumbs as the script does: snapped to step, in order, and from the track and the number fields. It brings its own label, help and error, so it goes outside a Field.
| Prop | Values | Default |
|---|---|---|
label |
The slider’s name, beside its value; with two thumbs, the group’s | Required |
value |
A number, or [min, max] for two thumbs, which the application changes in onValueChange |
Its own state |
defaultValue |
The value it starts with when the application does not set value, which a form’s reset brings back |
The middle of min and max |
onValueChange |
(value), called with the new value, shaped as value, when a thumb moves |
None |
min, max, step |
Numbers, on each range input | 0, 100, 1 |
name |
The range input’s name, or two names for two thumbs | None |
help |
Help text after the slider, which describes each range input | None |
error |
An error message after the help, which also makes each range input invalid | None |
disabled |
true disables the range inputs and the number fields |
false |
aria-disabled |
true looks like disabled and blocks changes, but keeps the values in the form |
None |
thumbLabels |
The two thumbs’ names, in visually hidden labels | The label with minimum and maximum |
numberLabels |
One label per thumb, each adding a number field under the track that follows its thumb | None |
Children follow the value, such as a unit. The other props are the container div’s, className and ref included.
CSS variables
Override these variables on a root, a slider or its control, not on one input alone.
| Variable | Default |
|---|---|
--plf-slider-track-height |
--plf-space-1, 0. (4px) |
--plf-slider-thumb-size |
--plf-space-4, 1rem (16px) |
--plf-slider-control-height |
--plf-control-height-md, 2. (36px) |
--plf-slider-track-bg |
--plf-color-input |
--plf-slider-fill-bg |
--plf-color-primary; danger on an invalid input |
--plf-slider-thumb-bg |
--plf-color-surface |
--plf-slider-thumb-border |
The fill color |
--plf-slider-thumb-shadow |
--plf-shadow-xs |
--plf-slider-focus-color |
--plf-focus-color |
Sliders are horizontal with one or two thumbs; vertical sliders, marks and tooltips are not included.