Skip to main content

Slider

<zeno-slider>FormsForm controlSource

Picks a number from a range by dragging or with the arrow keys.

import '@usezeno/tokens/css';
import '@usezeno/core/web-components';

Examples​

Basic​

min, max and step set the range. The input event fires while the value moves and change fires when it is set. Both carry the number in event.detail.value.

Value: 16

<zeno-slider label="Font size" min="12" max="24" step="2" value="16"></zeno-slider>
<p data-result>Value: 16</p>
document.querySelector('zeno-slider').addEventListener('input', event => {
document.querySelector('[data-result]').textContent = 'Value: ' + event.detail.value;
});

Sizes​

<zeno-slider label="Small" size="sm" value="25"></zeno-slider>
<zeno-slider label="Medium" size="md" value="50"></zeno-slider>
<zeno-slider label="Large" size="lg" value="75"></zeno-slider>

Marks​

show-marks draws a tick at the minimum and at the maximum. The marks property takes a list of values, each with an optional label. The labels are drawn below the element’s own box, so this example leaves space under each slider.

<div style="padding-bottom: 2rem">
<zeno-slider label="Brightness" value="30" show-marks></zeno-slider>
</div>
<div style="padding-bottom: 2rem">
<zeno-slider label="Quality" value="50" step="50"></zeno-slider>
</div>
document.querySelectorAll('zeno-slider')[1].marks = [
{ value: 0, label: 'Low' },
{ value: 50, label: 'Medium' },
{ value: 100, label: 'High' },
];

States​

The error text shows below the slider and colours the fill.

<zeno-slider label="Disabled" value="60" disabled></zeno-slider>
<zeno-slider label="With an error" value="90" error="Choose 80 or less."></zeno-slider>

In a form​

A slider always has a value, so it is always sent with the form. With no value it sends the minimum.

Save Reset

Nothing submitted yet.

<form>
<zeno-slider name="volume" label="Volume" value="40"></zeno-slider>
<zeno-button type="submit">Save</zeno-button>
<zeno-button type="reset" variant="ghost">Reset</zeno-button>
<p data-result>Nothing submitted yet.</p>
</form>
const form = document.querySelector('form');
form.addEventListener('submit', event => {
event.preventDefault();
const sent = [...new FormData(form)].map(([name, value]) => name + '=' + value);
document.querySelector('[data-result]').textContent = 'Submitted: ' + sent.join('&');
});

Attributes and properties​

PropertyAttributeTypeDefaultDescription
minminnumber0
maxmaxnumber100
stepstepnumber1
sizesizereflects'sm' | 'md' | 'lg''md'
showTooltipshow-tooltipreflectsbooleanfalse
showMarksshow-marksreflectsbooleanfalse
marksmarksArray<{ value: number; label?: string }>
formatTooltip(_value: number) => string
formatValue(_value: number) => string
valuevalueFormValue'' From FormFieldMixin.
namenamereflectsstring From FormFieldMixin.
requiredrequiredreflectsbooleanfalse From FormFieldMixin.
disableddisabledreflectsbooleanfalse From FormFieldMixin.
readonlyreadonlyreflectsbooleanfalse From FormFieldMixin.
errorerrorstringAn error to show, for example one a server returned. From FormFieldMixin.
labellabelstringA visible label. An outside <label for> works as well. From FormFieldMixin.
hideRequiredIndicatorhide-required-indicatorbooleanfalse From FormFieldMixin.
touchedbooleanfalseTrue once the user has left the control or a submit was refused. From FormFieldMixin.
dirtybooleanfalseTrue once the user has changed the value. From FormFieldMixin.
defaultValueFormValue''The value the control goes back to when its form is reset. From FormFieldMixin.
formread onlyHTMLFormElement | null From FormFieldMixin.
labelsread onlyNodeList From FormFieldMixin.
validityread onlyValidityState From FormFieldMixin.
validationMessageread onlystring From FormFieldMixin.
willValidateread onlyboolean From FormFieldMixin.
isDisabledread onlybooleanTrue when the element or an ancestor fieldset disables it. From FormFieldMixin.
invalidread onlybooleanTrue when the control should look invalid. From FormFieldMixin.
testIdstringTest ID for automated testing From ZenoElement.

Methods​

MethodDescription
focus(options?: FocusOptions): voidFocus the component or its first focusable element From ZenoElement.
blur(): voidBlur the component or its focused element From ZenoElement.
checkValidity(): booleanReports whether the value is valid without showing anything. Use reportValidity() or validate() to show the result as well. From FormFieldMixin.
reportValidity(): boolean From FormFieldMixin.
setCustomValidity(message: string): void From FormFieldMixin.
validate(): booleanChecks validity and shows the result on the control. From FormFieldMixin.

Events​

EventDetailDescription
input{ value: number }The value changed while dragging.
change{ value: number }The value was committed.

Slots​

This element has no slots.

CSS parts​

Part
base
error
fill
label
marks
thumb
tooltip
track

CSS custom properties​

This element documents no custom properties of its own. Style it through its parts and through the tokens it reads.

The element's own source reads no tokens.

Types​

type FormValue = string | number | boolean | Date | null | undefined;

Accessibility​

Keyboard​

KeyWhat it does
TabMoves focus to the slider.
ArrowRightArrowUpRaises the value by one step.
ArrowLeftArrowDownLowers the value by one step.
HomeEndSets the value to the minimum or the maximum.
PageUpPageDownRaises or lowers the value by a larger amount. The browser sets the amount.

Forms​

  • With a name, the element adds its value to the data of the form it is in, and is left out while it is disabled.
  • It is labelled by its label attribute or by a <label for> that points at its id.
  • It takes part in validation: checkValidity(), reportValidity() and setCustomValidity() work, and an invalid element blocks the submit and matches :invalid.
  • It follows a <fieldset disabled> around it and goes back to its first value when the form is reset.
  • The messages it writes itself, such as “Please fill out this field.”, are in English only.

Notes​

  • The control is a native <input type="range">. It lies over the drawn track and is transparent, so pointer and keyboard input go to the native input. All keys in the table come from it.
  • The drawn thumb has role="presentation". The track, fill and marks are plain elements with no role.
  • The label attribute renders a <label> for the input. Without it, the name comes from an outside <label for> or from aria-label on the element.
  • The input has aria-valuetext with the value as text. Set the formatValue property to a function to read the value with a unit.
  • When the slider is invalid, the input has aria-invalid="true" and aria-describedby points at the error text.

Tests and known gaps​

  • Tested in a real browser by slider.test.ts.
  • Checked with axe-core in the light and the dark theme.
  • Has no Storybook story.
30 of the 44 properties, methods, events, slots and parts above have no description in the source
  • the property min
  • the property max
  • the property step
  • the property size
  • the property showTooltip
  • the property showMarks
  • the property marks
  • the property formatTooltip
  • the property formatValue
  • the property value
  • the property name
  • the property required
  • the property disabled
  • the property readonly
  • the property hideRequiredIndicator
  • the property form
  • the property labels
  • the property validity
  • the property validationMessage
  • the property willValidate
  • the method reportValidity()
  • the method setCustomValidity()
  • the part base
  • the part error
  • the part fill
  • the part label
  • the part marks
  • the part thumb
  • the part tooltip
  • the part track

Known gaps:

  • The thumb and the show-tooltip bubble are inside the track, and the track has overflow: hidden. They are cut off at the edge of the track, so the round thumb and the tooltip do not show.
  • Keyboard focus has no visible indicator. The focus ring is a shadow on the thumb, which the track cuts off, and the native input is transparent.
  • The row of marks has no height, because every mark is positioned absolutely. Mark labels overlap the content that follows the slider.
  • The readonly attribute does nothing. A read-only slider can still be moved.
  • A value outside min and max is not clamped. The element submits the value as it is. The native input inside it is limited to the range, so the two do not agree.