Slider
A slider lets the user choose a value from within a continuous range by moving a thumb
along a track. It is one of the most commonly re-implemented widgets — yet the platform
already ships one. Reach for a native <input type="range"> first:
it is keyboard-operable, exposes its value to assistive technology, and respects user
preferences with no scripting at all.
Build the ARIA slider below only when the native control genuinely can’t meet the
need — for example a non-linear scale, a custom two-handle range, or visual requirements
the native thumb can’t express. When you do, you take on the full
WAI-ARIA Authoring
Practices slider contract: a focusable role="slider" thumb, the
aria-valuemin / aria-valuemax / aria-valuenow
trio, an accessible name, and the keyboard model documented here. The page is a
reference implementation: the markup is authored statically and
slider.js enhances it.
Live demo
Tab to the thumb, then use the arrow keys to nudge the value by one, Page Up / Page Down for a larger jump, and Home / End for the ends of the range. You can also drag the thumb with a pointer. The current value is shown both by the thumb’s position and by the text readout beside the label.
When to use
Prefer the native control first
- For a single value from a numeric range, use
<input type="range">with a real<label>— it is keyboard- and screen-reader-complete for free. - Pair any range input with a visible readout (and an explicit step) so the value is perceivable without dragging.
- Build this ARIA slider only when you need a non-linear scale, a custom thumb, a multi-handle range, or behaviour the native control can’t express — and budget for the keyboard model below.
- Whatever you choose, the control must carry an accessible name and announce its current value as it changes.
Markup
Author the thumb with its full ARIA value contract already in place, then let
slider.js manage interaction. With scripting off, the thumb is still a
named, value-bearing control — the script only adds keyboard and pointer behaviour and
keeps the position, fill, and readout in sync.
<div class="ewa-slider" data-slider>
<p class="ewa-slider__label" id="vol-label">Volume:
<span class="ewa-slider__readout" id="vol-readout">40%</span>
</p>
<div class="ewa-slider__track">
<div class="ewa-slider__fill" aria-hidden="true"></div>
<div class="ewa-slider__thumb" role="slider" tabindex="0"
aria-valuemin="0" aria-valuemax="100" aria-valuenow="40"
aria-label="Volume" data-readout="vol-readout"></div>
</div>
</div>
Keyboard interactions
Focus rests on the thumb. Every key acts directly on the value and the change is
announced through aria-valuenow, so a keyboard or screen-reader user can
set the value precisely without a pointer.
| Key | Action |
|---|---|
| Tab | Moves focus to the slider thumb. |
| Right Arrow / Up Arrow | Increases the value by one step. |
| Left Arrow / Down Arrow | Decreases the value by one step. |
| Page Up | Increases the value by a larger step (10). |
| Page Down | Decreases the value by a larger step (10). |
| Home | Sets the value to the minimum. |
| End | Sets the value to the maximum. |
ARIA roles, states, and properties
The thumb owns the slider role and the whole value contract. The minimum, maximum, and
current value are required; add aria-valuetext when a bare number would not
be meaningful (for example a label like “Medium” or “$20–$40”).
| Attribute | On | Purpose |
|---|---|---|
role="slider" |
Thumb | Identifies the focusable element as a slider control. |
tabindex="0" |
Thumb | Puts the thumb in the tab order so it is keyboard-focusable. |
aria-valuemin |
Thumb | The lowest value the slider can take. |
aria-valuemax |
Thumb | The highest value the slider can take. |
aria-valuenow |
Thumb | The current value; updated on every change so AT announces it. |
aria-valuetext |
Thumb | A human-readable value to announce when the number alone is not meaningful. |
aria-label / aria-labelledby |
Thumb | Gives the slider an accessible name (here, “Volume”). |
Common mistakes
Pitfalls to avoid
- Hiding the current value. Provide a visible text readout of the
value; the thumb position alone is hard to read precisely and useless to a
screen-reader user if
aria-valuenowis stale. - Reinventing the wheel. Check whether a native
<input type="range">meets the need first — it is accessible by default and far less code to maintain. - Failing non-text contrast. The thumb and track are graphical UI components: ensure they meet a 3:1 contrast ratio against adjacent colours (SC 1.4.11), and remap to system colours under forced-colors mode.
- Forgetting the accessible name. A slider with no
aria-labelor associated label is announced only as “slider” with no indication of what it controls. - Skipping
aria-valuetextwhen the number is meaningless. For ranges like price tiers or sizes, a bare number leaves the user guessing — announce the human-readable value instead.