Skip to content

Slider

hc-slider is applied to a native <input type="range">. Keyboard navigation (←/→, Home, End, PageUp, PageDown), form participation, and screen-reader announcement of role + value + range all come for free from the browser; only the visual chrome is replaced via appearance: none plus per-vendor pseudo-elements.

import { installSlider } from '@hypermedia-components/core';
installSlider();

Firefox renders the 0→value portion of the track natively via ::-moz-range-progress. WebKit and Chromium have no equivalent pseudo, so the same effect is painted with a linear-gradient that reads a --hc-slider-value custom property (a 0-100 percentage).

installSlider() keeps --hc-slider-value synchronised with each slider’s current value via the input event — call it once and forget. For server-rendered pages, write the property directly:

<input class="hc-slider" type="range"
min="0" max="100" value="40"
style="--hc-slider-value: 40">

That way the fill renders correctly on first paint even before JavaScript loads.

data-variant accepts success, warning, and error for non-default fill colors. The thumb border tracks the variant too.

data-size accepts sm, md (default), and lg. Track height and thumb size scale together.

Use the native disabled attribute. The track and thumb dim and the control stops responding to pointer and keyboard input.

Add data-orientation="vertical" to stand the slider up. This uses the modern, native approach — CSS writing-mode — so the control stays a real <input type="range">: the OS thumb, the full keyboard ( / step, Home / End, PageUp / PageDown), form participation, and screen-reader value announcement all keep working. The maximum sits at the top, so increases the value.

Set the height with the --hc-slider-length custom property (default 12rem):

<input class="hc-slider" type="range" data-orientation="vertical"
style="--hc-slider-length: 16rem">

The slider participates in form submissions like any other input. For instant updates, listen to input:

<input class="hc-slider"
type="range" min="0" max="100" value="40"
name="volume"
data-hx-post="/preferences/volume"
data-hx-trigger="input changed delay:200ms"
data-hx-include="this">
  • Always give the slider an accessible name — wrap it in a <label> or set aria-label.
  • The native input handles / (step), Home / End (min / max), PageUp / PageDown (large step) without any custom JS.
  • For ranges where the displayed value differs from the underlying number (e.g. percent of a non-100 max), set aria-valuetext="40 %" so screen readers announce the formatted string.
  • Don’t remove the focus outline. The thumb receives a box-shadow ring through --hc-color-focus-ring.

A native <input type="range"> is a single-thumb control. Multi- thumb range pickers (price range, brightness span, etc.) are out of scope for this component — that pattern requires a custom DOM shell and a much larger behavior to manage the two thumbs manually. Until that lands, two single sliders side-by-side (with linked min/max constraints in form-validation JS) is the recommended pattern.

Component tokens (in component.tokens.json):

Token pathPurpose
slider.track-height / track-bgTrack.
slider.thumb-size / thumb-bg / thumb-borderThumb.
slider.fillDefault fill color (action.primary).
slider.success-fill / warning-fill / error-fillVariant fills.
slider.success-thumb-border / warning-thumb-border / error-thumb-borderVariant thumb borders.
slider.disabled-fillDisabled thumb border color.
slider.radiusTrack + thumb corner radius.
slider.sm.* / lg.*Sized variants.
Show the generated CSS variables
--hc-slider-track-height | -track-bg | -radius
--hc-slider-thumb-size | -thumb-bg | -thumb-border
--hc-slider-fill | -success-fill | -warning-fill | -error-fill
--hc-slider-success-thumb-border | -warning-thumb-border | -error-thumb-border
--hc-slider-disabled-fill
--hc-slider-sm-track-height | -sm-thumb-size
--hc-slider-lg-track-height | -lg-thumb-size
--hc-slider-value (0-100, kept in sync by installSlider)
--hc-slider-length (vertical track length; default 12rem)
--hc-color-focus-ring (inherited from data-color)
  • Progress — for displaying a non-interactive measure of completion.
  • Input — text / number inputs share the focus ring contract.