HySlider
A form-associated horizontal range slider for selecting a numeric value within a bounded range. Layers a custom track, fill, and thumb over a transparent native <input type="range"> to retain full accessibility and keyboard support (arrow keys, PageUp/Down, Home/End) while allowing design-system-aligned styling.
Form Integration
Implements the Form-Associated Custom Elements API — the slider's value is included in FormData when the form is submitted under its name.
Keyboard
Native range input handles all keyboard interactions:
- Arrow keys: increment / decrement by
step - PageUp / PageDown: larger jumps (browser-defined)
- Home / End: jump to
min/max
Gradient / custom track
Use the track slot to overlay custom content (e.g., a color gradient for hue/chroma/lightness sliders). Hide the solid fill via CSS part:
hy-slider.rainbow::part(fill) {
display: none;
}Examples
Basic usage
<hy-slider label="Spacing step" min="1" max="8" value="4"></hy-slider>With hint, suffix, and variant
<hy-slider
label="Motion speed"
hint="0 = instant, 1 = languid"
min="0"
max="1"
step="0.01"
value="0.5"
suffix="s"
variant="brand"
>
</hy-slider>Color slider with gradient track
<hy-slider label="Hue" min="0" max="360" value="180" suffix="°">
<div
slot="track"
style="background: linear-gradient(to right, hsl(0,80%,50%), hsl(60,80%,50%), hsl(120,80%,50%), hsl(180,80%,50%), hsl(240,80%,50%), hsl(300,80%,50%), hsl(360,80%,50%));"
></div>
</hy-slider>Error state
<hy-slider label="Volume" error error-message="Value exceeds safe listening level"> </hy-slider>Discrete slider with tick marks and min/max labels
Opt in to ticks when the slider snaps to sparse stops — without marks, step-snapping can feel like cursor lag. Add tick-labels to anchor the scale with min/max readouts below the track. tick-labels is a no-op without ticks.
<hy-slider label="Base radius" min="0" max="8" step="1" value="4" suffix="px" ticks tick-labels>
</hy-slider>Sparse, designer-named tick marks (compass directions, t-shirt sizes, …)
Use tickMarks to mark specific stops by value with optional labels. The slider keeps its step granularity for fine-grained drag; tick marks are visual references. Set tickSnap if you want the slider to restrict to those values.
const slider = document.querySelector('hy-slider'); slider.tickMarks = [ { value: 0, label: 'T',
ariaLabel: 'Top' }, { value: 90, label: 'R', ariaLabel: 'Right' }, { value: 180, label: 'B',
ariaLabel: 'Bottom' }, { value: 270, label: 'L', ariaLabel: 'Left' }, ];<hy-slider label="Light angle" min="0" max="360" step="1"></hy-slider>Snap-to-tickMarks slider (discrete picker disguised as a slider)
const slider = document.querySelector('hy-slider'); slider.tickMarks = [ { value: 0, label: 'S' }, {
value: 1, label: 'M' }, { value: 2, label: 'L' }, { value: 3, label: 'XL' }, ];<hy-slider label="Size" min="0" max="3" tick-snap></hy-slider>Fractional step with auto-inferred precision
Without any precision hint, 0.357 dragged through float math can render with trailing noise like 0.357…04. By default the component rounds the displayed value to the decimal count implied by step — step="0.01" → 2 decimals.
<hy-slider label="Chroma" min="0" max="1" step="0.01" value="0.357"></hy-slider>
<!-- readout: 0.36 -->Explicit display precision
Override the auto-inferred precision — useful when step is coarser than the precision you want to show (e.g. step=1 but you want one decimal).
<hy-slider label="Zoom" step="1" value="42" display-precision="1"></hy-slider>
<!-- readout: 42.0 -->Custom formatter — percentage
When you need to reshape the number entirely (scale, locale, custom units) pass formatValue as a property binding. When set, the formatter owns the full string — the suffix prop is NOT appended.
const slider = document.querySelector('hy-slider');
slider.formatValue = (v) => `${(v * 100).toFixed(1)}%`;
slider.value = 0.357; // readout: "35.7%"Inline layout (dense parameter panels)
Label + hint sit on the left of the row, slider in the middle, value on the right — one row per parameter. Set --hy-slider-label-column-width on a wrapping element so stacked sliders align.
<div style="--hy-slider-label-column-width: 6rem;">
<hy-slider
layout="inline"
label="Hue"
hint="color angle"
min="0"
max="360"
value="208"
suffix="°"
></hy-slider>
<hy-slider
layout="inline"
label="Chroma"
hint="saturation"
min="0"
max="1"
step="0.01"
value="0.65"
></hy-slider>
<hy-slider
layout="inline"
label="Vibrancy"
hint="intensity"
min="0"
max="2"
step="0.01"
value="0.60"
></hy-slider>
</div>Form submission
<form>
<hy-slider name="brightness" min="0" max="100" value="75"></hy-slider>
<button type="submit">Save</button>
</form>Programmatic control
const slider = document.querySelector('hy-slider');
slider.stepUp(); // Advance by one step
slider.stepDown(5); // Retreat by five steps
slider.value = 42; // Set directly
slider.focus();Events
- input - Fired during drag / keyboard adjustment. Detail:
- change - Fired when the value is committed (pointer release / after key). Detail:
Slots
- track - Custom content inside the track, behind the fill (e.g. a gradient overlay).
Methods
checkValidity()
Checks if the slider's current value satisfies its constraints.
reportValidity()
Checks validity and reports any errors to the user.
focus()
Focuses the underlying range input.
blur()
Removes focus from the underlying range input.
stepUp()
Increments the value by n steps (defaults to 1). Clamps to max. Dispatches input and change events. No-op if disabled.
stepDown()
Decrements the value by n steps (defaults to 1). Clamps to min. Dispatches input and change events. No-op if disabled.