Liking cljdoc? Tell your friends :D

x-range-slider

A dual-handle, form-associated, accessible range slider web component. Two draggable thumbs select a numeric [start, end] sub-range within [min, max].

For a single-value slider, use x-slider instead.

Tag name

<x-range-slider></x-range-slider>

Attributes

AttributeTypeDefaultDescription
startstring (number)minLower selected value
endstring (number)maxUpper selected value
minstring (number)"0"Track minimum
maxstring (number)"100"Track maximum
stepstring (number | "any")"1"Step increment. "any" disables stepping.
min-gapstring (number)"0"Minimum distance enforced between start and end
disabledboolean (presence)falseDisables all interaction; removes thumbs from the tab order
readonlyboolean (presence)falseBlocks pointer and keyboard changes; thumbs remain focusable
namestringForm field name
labelstringVisible label text above the slider
show-valueboolean (presence)falseShow the current start – end text beside the label
size"sm" | "md" | "lg""md"Size variant
aria-labelstringAccessible label for the slider group and thumbs
aria-labelledbystringForwarded to [part=base]
aria-describedbystringForwarded to [part=base]

Properties

All properties reflect to their corresponding attributes.

PropertyTypeReflects attribute
startstringstart
endstringend
minstringmin
maxstringmax
stepstringstep
minGapstringmin-gap
disabledbooleandisabled
readOnlybooleanreadonly
showValuebooleanshow-value
namestringname
labelstringlabel
sizestringsize

Events

EventCancelableDetail
x-range-slider-change-requestyes{ start, end, previousStart, previousEnd, min, max } — call preventDefault() to block the update
x-range-slider-inputno{ start, end, min, max }
x-range-slider-changeno{ start, end, min, max }

All detail fields are numbers. All events bubble and are composed (cross the shadow-DOM boundary).

  • x-range-slider-change-request — fires before either value updates. Prevent to keep the current range (controlled mode).
  • x-range-slider-input — fires continuously while a thumb is dragged and on every keyboard change.
  • x-range-slider-change — fires once when a drag is committed (pointerup) and after every keyboard change.

Each event always carries the full { start, end } pair regardless of which thumb moved.


Behavior

  • No crossing. When a thumb is dragged or stepped toward the other, it stops at the other thumb's value — start can never exceed end. The thumbs never swap roles.
  • min-gap. The two values are kept at least min-gap apart. While dragging, the moving thumb stops min-gap short of the other.
  • Out-of-order attributes. If start and end are set declaratively in a way that violates the order or the gap, the component resolves them deterministically: end is pulled up to satisfy the gap; only when that would exceed max is start pulled down instead. For predictable stepping, set min-gap to a multiple of step.
  • Step snapping. Dragged and stepped values snap to step (measured from min). step="any" disables snapping.
  • Track click. Clicking the bare track moves the nearest thumb to that position and begins dragging it.
  • Overlapping thumbs. When both values coincide, the last-grabbed thumb stays on top. A pointer-down at or below the shared position grabs the start thumb; above it grabs the end thumb.

Parts

PartElementDescription
base<div>Outer wrapper; role="group"; receives data-size
header<div>Row containing label and value text; hidden when neither is active
label-text<span>Label text
value-text<span>start – end display
track<div>The rail region
track-fill<div>Highlighted segment between the two thumbs
thumb-start<div>Lower handle; role="slider"
thumb-end<div>Upper handle; role="slider"

CSS Custom Properties

PropertyDefault (light)Description
--x-range-slider-track-colorrgba(0,0,0,0.15)Unfilled track color
--x-range-slider-fill-color#3b82f6Selected-segment color
--x-range-slider-thumb-color#ffffffThumb background color
--x-range-slider-thumb-border2px solid #3b82f6Thumb border
--x-range-slider-thumb-shadow0 1px 4px rgba(0,0,0,0.20)Thumb drop shadow
--x-range-slider-focus-ring#60a5faFocus ring color
--x-range-slider-disabled-opacity0.45Opacity when disabled
--x-range-slider-label-colorrgba(0,0,0,0.60)Label text color
--x-range-slider-value-colorrgba(0,0,0,0.50)Value text color
--x-range-slider-radius9999pxTrack and fill border-radius

Dark-mode overrides are applied automatically via @media (prefers-color-scheme: dark).

Size-driven internal variables

The size attribute sets CSS custom properties on [part=base]:

SizeTrack heightThumb size
sm4px14px
md6px18px
lg8px22px

Accessibility

  • Each thumb is a role="slider" element with its own tabindex, aria-valuemin, aria-valuemax, aria-valuenow and aria-valuetext.
  • The thumbs advertise their effective movable range: the start thumb's aria-valuemax is end - min-gap; the end thumb's aria-valuemin is start + min-gap.
  • [part=base] is role="group" and carries the forwarded aria-label / aria-labelledby / aria-describedby. Each thumb is labelled "<name> minimum" / "<name> maximum", where <name> is aria-label, label, or "Range".
  • Keyboard: arrow keys move a thumb by one step (ten with Shift), PageUp / PageDown move by ten steps, Home / End jump to min / max. When step is any, keyboard moves use an increment of 1.
  • When disabled, both thumbs receive tabindex="-1" and aria-disabled.
  • readonly keeps the thumbs focusable but consumes value-changing keys.

Form association

x-range-slider is form-associated (formAssociated = true). The current range is submitted under the name attribute as a single comma-joined string "start,end" (e.g. "20,80"); split on , to read the two values. Form reset restores the widest range (startmin, endmax).


Responsive

On touch devices (@media (pointer:coarse)) the thumbs are enlarged to 28px for easier interaction. The track adapts to its container width.


Usage examples

Basic range slider

<x-range-slider start="20" end="80" min="0" max="100"></x-range-slider>

With label and visible value

<x-range-slider label="Price" show-value start="200" end="800"
                min="0" max="1000" step="50"></x-range-slider>

Minimum gap between thumbs

<x-range-slider start="30" end="70" min="0" max="100"
                min-gap="10"></x-range-slider>

Disabled / readonly

<x-range-slider start="25" end="75" disabled></x-range-slider>
<x-range-slider start="25" end="75" readonly></x-range-slider>

Sizes

<x-range-slider size="sm" start="20" end="60"></x-range-slider>
<x-range-slider size="md" start="20" end="60"></x-range-slider>
<x-range-slider size="lg" start="20" end="60"></x-range-slider>

In a form

<form>
  <x-range-slider name="price" start="200" end="800" min="0" max="1000"
                  label="Price range" show-value></x-range-slider>
  <button type="submit">Search</button>
</form>

JavaScript API

const slider = document.querySelector('x-range-slider');

slider.start = '30';
slider.end = '70';
slider.min = '0';
slider.max = '100';
slider.step = '5';
slider.minGap = '10';

slider.addEventListener('x-range-slider-input', (e) => {
  console.log('dragging:', e.detail.start, e.detail.end);
});
slider.addEventListener('x-range-slider-change', (e) => {
  console.log('committed:', e.detail.start, e.detail.end);
});

// Controlled mode — veto changes
slider.addEventListener('x-range-slider-change-request', (e) => {
  if (e.detail.end - e.detail.start < 5) e.preventDefault();
});

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close