Skip to content

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:

css
hy-slider.rainbow::part(fill) {
  display: none;
}

Examples

Basic usage

html
<hy-slider label="Spacing step" min="1" max="8" value="4"></hy-slider>

With hint, suffix, and variant

html
<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

html
<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

html
<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.

html
<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.

html
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' }, ];
html
<hy-slider label="Light angle" min="0" max="360" step="1"></hy-slider>

Snap-to-tickMarks slider (discrete picker disguised as a slider)

html
const slider = document.querySelector('hy-slider'); slider.tickMarks = [ { value: 0, label: 'S' }, {
value: 1, label: 'M' }, { value: 2, label: 'L' }, { value: 3, label: 'XL' }, ];
html
<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.

html
<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).

html
<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.

css
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.

html
<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

html
<form>
  <hy-slider name="brightness" min="0" max="100" value="75"></hy-slider>
  <button type="submit">Save</button>
</form>

Programmatic control

javascript
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.

Built with Lit. Documented with VitePress.