Posted Mar 8, 2020
Dave Rupert recently wrote a great post lamenting the fact that HTML doesn't actually live up to its promise of being accessible by default.
Now, to be fair, some of the issues that he mentions aren't the fault of HTML, but are actually failures of assistive technologies. A case in point being the issues with the HTML number input that the good folks at gov.uk recently found. All of the accessibility issues they discovered were problems with either Dragon NaturallySpeaking or NVDA—not the input itself.
That being said, Dave's point still really resonated with me—accessibility is hard enough without browser and assistive technology vendors making it harder by not doing their part of the job. NVDA and Firefox are both produced by non-profits, so I'm happy to give them a pass. But all of the other characters in this story are making money. So what's their excuse?
Range rage
In his post, Dave made a call for other examples of these kinds of issues, and one immediately popped into my head: the HTML range input. This is one that I've found particularly frustrating, because it almost works. But not quite.
The range input has a number of attributes that allow you to customize it. The basic ones are min, max, and step. The min and max attributes are fairly self-explanatory. The step attribute allows you to control the increments between those two values. All of these attributes work fine, except for one problem: Talkback will always announce the value as a percentage, regardless of what they're set to.
Note: You can follow along at home using this test page. All testing was done on Android 10 with Android Accessibility Suite 8.1.
Consider the following example:
<input type="range" min="0" max="10" step="0.5">
In all the other screen readers I tested, this worked as expected: it announces values from 0 to 10, incrementing by 0.5 each time. In Talkback, however, it announces these values as 0% to 100%, incrementing by 5% each time.
This may not seem like a big issue, since it's easy to the do the conversion math in your head. But what if you have different values?
<input type="range" min="3" max="124" step="0.357">
Unless you're Alan Turing reincarnated, that's not going to be a usable input.
ARIA to the rescue?
ARIA has properties that duplicate the min and max: aria-valuemin and aria-valuemax. There's also an aria-valuenow for announcing the current value (please note that this value would need to be updated via Javascript in the real world, but the examples here will just be static). These ARIA attributes are meant for reproducing the semantics in case you need to build a custom range input—but you might think that we could use them to force the result that we want:
<input type="range" min="0" max="10" step="0.5" aria-valuemin="0" aria-valuemax="10" aria-valuenow="5"> <!-- aria-valuenow would need to be updated in real time via Javascript in the real world -->
Unfortunately, Talkback blissfully ignores these attributes and keeps announcing percentages. It is worth noting that aria-valuenow does seem to override the value—in the above example, Talkback will announce the value as "50%" regardless of what the actual value of the input is. But this doesn't really help us.
There's one last ARIA attribute that could help us: aria-valuetext. This one is meant for giving a text value instead of a numerical one. An example could be a customer rating widget where we ask them to choose a value from "very unhappy" to "very happy" instead of a number.
<input type="range" min="0" max="10" step="0.5" aria-valuemin="0" aria-valuemax="5" aria-valuenow="0" aria-valuetext="Very unhappy with Talkback">
In theory, we could abuse this to insert our preferred numerical value instead, but unfortunately this not only doesn't work, it actually seems to just break the input completely. Talkback just doesn't announce anything, and I can't seem to adjust the value more than once without blurring and refocusing it.
But wait, there's more
The only way I can think of to get around all of this would be to build a custom slider widget that outputs its value using an aria-live region. But even there we have issues because Talkback uses the up and down volume keys for controlling the value of the input—something that we can't replicate in a custom element because these events aren't exposed in the DOM (something you should keep in mind before attempting to use the ARIA Authoring Practices pattern for sliders).
We would have to come up with a completely different interaction model, probably using buttons to increment/decrement (in which case we're not really building a range input anymore).
What's a designer/developer to do?
My personal recommendation is that it's still OK to use the range input—just make sure you have a redundant number… ahem… text input right next to it. <sigh>
Why can't we have nice things?
In many ways, this issue and the others called out by Dave remind me of the earlier days of the internet. Before we had standards-compliant browsers. When nothing just worked, and we had to resort to all manner of workarounds and hacks just to get our websites to work cross-browser.
Unfortunately it's already hard enough to get folks to care about whether or not their site or app is accessible—especially where cost is an issue. Start throwing complicating factors like this into the mix and it can become downright impossible to get decision-makers to do the right thing.
What's worse, even the people who do care about doing the right thing can become frustrated and give up. Designers and developers already have enough challenges to solve without having to deal with nonsense like this.
We should follow Dave's example and call out these issues where we see them—whether it's a problem with the HTML spec, a browser, or an assistive technology. The web should be accessible by default.