Search topics
Range sliders that only move by dragging
A price slider's thumbs are plain elements moved by pointer events, so they can't be focused, have no value a screen reader can read, and can't be set without a drag.
<span class="thumb"> The problem
People who can't drag, and screen reader users, can't set the price range or find out what it is.
A shop's product list has a price filter: a track from $0 to $200 with two round thumbs, and "$20 – $160" written above it. With a mouse, you press on a thumb, slide it, and the products update when you let go. Press Tab and focus jumps from the category list straight to the Apply button: neither thumb can take focus. A screen reader reads "Price, $20 – $160" as text, if it reaches it at all, and nothing it can change. On a phone, a thumb is small enough that a press often lands beside it, and the page scrolls instead.
The thumbs are span elements moved by pointer events, so the filter fails three criteria at once. Nothing can be done from the keyboard, so it fails 2.1.1. The thumbs have no role, name or value, so a screen reader can't say what they are or where they are set, which fails 4.1.2. And the only way to set a price is to drag, which fails 2.5.7: picking a price is not a task that needs a drag.
The same failure comes in quieter forms. A thumb may have role="slider" and tabindex="0" but no key handler, so it takes focus and then ignores the arrows. It may move with the arrows while its aria-valuenow stays at the value it loaded with. It may read "20" with no unit, or two thumbs may both be called "Price". Keyboard support doesn't settle 2.5.7 either: the criterion asks for a way that works with a single pointer, and a person on a touch screen has no arrow keys.
A price or date filter is often the only way to narrow a long list, so a slider no one else can move leaves people scrolling through every product. On a phone, the thumbs are usually smaller than the 24 pixels most other controls get, which makes them hard to catch for anyone.
4 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (affected)
- Reach, strength (affected)
- Cognitive (not affected)
- Seizures (not affected)
- Limited manipulation Keyboard, switch and voice control users can't press and hold while moving, and the thumbs aren't in the Tab order, so the price range stays where it started.
- Without vision Screen reader users find no control and no value: the range is two empty spans and a line of text the reader may never reach.
- Limited reach and strength People with tremors or weak grip lose the thumb halfway, or let go a step or two from where they meant to.
- Limited vision With a magnifier, the thumb and the price it shows can sit in different parts of the screen, so setting a value is trial and error.
A scanner sees two empty spans and a line of text, and finds nothing wrong: spans need no name, and nothing marks them as a control. axe reports a role="slider" with no name or no aria-valuenow, but not one whose arrows do nothing or whose value never changes; only pressing the keys shows that. Asked to fix the slider, code assistants often add role="slider" and tabindex="0" and stop there, which puts a silent, stuck control in the Tab order. They rarely add a way to set the value without dragging, because nothing in the markup asks for one.
Try it
Drag a thumb to change the price range. Then put the mouse aside and try it with Tab and the arrow keys.
The panel shows what a screen reader announces. Can you set a price without dragging, and do you hear it?
Broken Can you fix this?
Price$20 – $160
Screen reader says:
(Tab to the price filter)
The fix
Give each end of the range a name, a value it reads out, and a way to set it with keys and with single taps.
- 1Each end of the range takes focus and moves with the arrow keys.
- 2Each end has a name and reads its value with the unit.
- 3Every value can be set with clicks, taps or typing, not only a drag.
<div class="price"> <span class="price-label">Price</span> <span class="price-values">$20 – $160</span> <div class="track"> <span class="thumb" data-thumb="min" style="left: 10%"></span> <span class="thumb" data-thumb="max" style="left: 80%"></span> </div></div>Two native range inputs
<fieldset class="price"> <legend>Price</legend> <label for="price-min">Minimum</label> <input type="range" id="price-min" min="0" max="200" step="10" value="20" aria-valuetext="$20"> <output for="price-min">$20</output> <label for="price-max">Maximum</label> <input type="range" id="price-max" min="0" max="200" step="10" value="160" aria-valuetext="$160"> <output for="price-max">$160</output></fieldset>Why this fix: Use native HTML first
The thumbs can't take focus, so the keyboard can't reach them. They have no role, name or value, so assistive technology doesn't know they are controls. And pointer events are the only way in, so every price needs a drag.
The browser gives each input focus, the arrow keys, Page Up, Page Down, Home and End, and a role and value a screen reader reads. A click or tap on the track moves the thumb there, and because that is the browser's own behaviour, 2.5.7 leaves it to the browser. aria-valuetext makes the value read as "$20" rather than "20", and the legend and labels name each end "Price, Minimum". The cost is the look: two tracks, one under the other, rather than one with two thumbs. Don't lay the two inputs over each other on one track with pointer-events: none: that turns off the click on the track, and the drag becomes the only pointer action again.
All three pass. The native range inputs take the least code and get keys, values and the click on the track from the browser; choose them when two tracks are acceptable in the design. The custom slider keeps one track with two thumbs, but you write and test the keys, the values and the track click yourself; choose it when the design needs one track and the team can test it with screen readers. The number fields leave an existing slider untouched and add exact typing for everyone; choose them when the slider comes from a library you can't change, or when people need precise values, such as a mortgage or a date range.
The value a screen reader hears is aria-valuetext when it is set, and aria-valuenow when it is not. Use it whenever the number alone isn't the value: "$20", "3 nights", "Wednesday". Keep it short, and keep the name out of it: the name already says "Minimum price".
A few things decide how the slider behaves once it is in a page.
- Applying the filter: if the products reload on every change, an arrow key press reloads the page, and a screen reader hears the list change ten times. Wait until the key is released for a moment, or use an Apply button, and say the result count in a status region.
- Vertical sliders: set
aria-orientation="vertical"on a custom slider, and make Up raise the value. Native range inputs can be drawn vertically withwriting-mode: vertical-lr. - Touch size: the thumbs and the track should take a tap of at least 24 by 24 pixels; make the hit area larger than the drawn thumb with padding or a pseudo-element.
- Forced colors: draw the thumbs and the filled part of the track with borders or
currentColor, so they don't vanish in a contrast theme.
Slider libraries vary. Some ship role, keys and values but no track click; some set aria-valuenow but no aria-valuetext. Check what the element that takes focus exposes, not what the library's documentation promises.
Fixing this with an AI coding assistant? Get this guide as Markdown
Verify the fix
5 checks.
Test with: Keyboard, Screen reader, Mouse, Touch
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the slider component or its library changes.
Limits
This is a starting pattern, not a guarantee for every application. Screen readers differ in how they read range inputs and custom sliders: some read the value before the name, and some on iOS move a slider by swiping up and down rather than with keys. Sliders that pick a colour, set a time on a media player, or resize a panel have needs of their own and are not covered here. If your "slider" is a row of slides with arrows, see carousels that keyboard and screen reader users can't use. Test the complete filter journey with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.