Accessibility Testing is Essential for Creating a Good User Experience
Accessibility is a part of usability that improves the user experience for everyone, and yet so many project teams I've worked with spend almost none of their time on it, if any. When I bring it up, they acknowledge it as important, but the expectation is generally that the engineers can just make their code comply with the Web Content Accessibility Guidelines (WCAG) and the app will be fully accessible to all.
Let me be very clear to anyone who participates in building software: writing WCAG-compliant code is not enough! As my volunteer team has built out a resource site for Washtenaw County ID holders , we've discovered a number of accessibility issues in code that follows all the rules.
Testing your own application can help you catch obviously bad experiences before you get feedback from your users and fine-tune. As an industry, we know this is true and we regularly test our apps with a keyboard, a mouse, a monitor, and/or a touch-screen device before we put functionality in front of our users. We think we would never release an obviously bad user experience, but we do it all the time, because we're not testing our own apps with accessibility in mind.
Inputs and Labels on Android Firefox and TalkBack
"Every input needs a label" - most developers I've met know about this regardless of their level of knowledge of digital accessibility. And they all know you can either nest the input inside the label or associate them via the input's ID. We're told they both work the same way, but they actually don't.
the following is an HTML code sample
<!-- These are not equivalent! -->
<label>
Name
<input />
</label>
<label for="name">Name</label>
<input id="name" />
As of this writing, labels and inputs associated only by the "id" attribute provide a worse experience on Android TalkBack in the latest Firefox. When the user focuses the label, TalkBack reads the label twice. This won't prevent most users from using the input, but it's potentially confusing.
When my team ran into this issue, we couldn't find any documentation of it online, but we figured out the cause through experimentation. Nesting the input in the label was very easy for us to do, but we wouldn't have known to do it if we hadn't been testing with a wide range of platforms and screen readers.
Table with Table Header and Caption Elements on iOS
Inputs and labels showed us that elements used correctly according to their documentation don't always provide the best experience. More complex elements require more testing to make sure they work as you expect. Various screen readers are known to have issues describing tables - this was mentioned specifically as part of my early education in accessibility.
When we were building a table for our web app, we were extra careful to follow best practices. However, when we tested the table on iOS with VoiceOver, it described the table saying, "Data table<caption>, row negative ninety septillion, twenty quintiliion, twenty-three quadrillion, three-hundred seventy-two trillion, thirty-six billion, eight-hundred fifty-four million, seven-hundred seventy-five thousand, eight-hundred eight, table start..."
That number stuck out to us as oddly specific - we didn't even have any numbers in the table, and it only had two columns and a few rows.With some searching we realized that it's the minimum signed 64-bit integer, except it has two zeroes after each of the first two digits. In lay terms, it’s a number that can easily show up because of a common kind of bug.
It's a bizarre experience for a user to hear that when trying to understand a table, not least because they might think the number is data from the table itself. Even if they understand what's going on, it takes about 12 seconds just to read that number at the default VoiceOver reading speed! Can you imagine having to wait 12 seconds just to hear the next part of the table?
So what was going on? Our search also led us to a page on PowerMapper where this issue has been documented since iOS 13 , which came out in 2019 (over 5 years ago now!). This page was very helpful to understand the cause and solution. Testing confirmed that having a caption and table headers in the table was the root cause of the issue. Captions are the standard way to label an HTML table according to the Mozilla Developer Network caption element page and the World Wide Web Consortium (W3C) caption and summary page , so this is another example of best practices leading to a bad experience.
We found other issues with our table, including one header being read when a different header was selected. Considering this, the small number of columns in our data, and the fact that we expect most of our users to be on mobile devices, we decided to structure the page differently and avoid the table altogether. This was easy for us, but other developers with the same problem may have to keep the table and find another way around the issue. It's important to consider the constraints of your product and target users, and experiment to find a way to improve the experience within those constraints.
Focus trap that doesn't trap focus
We were building a collapsible menu to contain the site's navigation links in narrow windows where the links wouldn't fit across the top of the page. Our first idea was to cover the entire page with the menu and trap the user's focus until they closed the menu or activated one of the links. The focus trap would cycle their focus to the top of the menu if they tried to tab past the last item.
Let me be clear, this is the wrong way to implement a collapsing menu! According to the W3C's Web Accessibility Initiative's (WAI) pages about the Menu Button Pattern and the Menu and Menubar Pattern , menus should not capture focus. We didn't know that at the time, but testing our implementation for the experience with a screen reader helped us figure it out.
The way we made this work was by writing a relatively complex set of functions that would run when the user pressed a key with focus on or in the menu. That should have been our first clue - if you're implementing a lot of JavaScript to do something you find on most websites, you might just be building a custom widget. And if you're doing that, you should first check to see if there's a native HTML element that can do what you want. In our case, the details element does everything we need.
We didn't find the details element, and we also didn't take the next best step, which is to look around the internet for a guide on the best practices for the pattern you're implementing. The WAI ARIA Authoring Practices Guide is a great place to start, and would have told us not to trap focus in this case.
Doing none of that, we plowed ahead with our implementation and ran into the problem. When you move focus to the next item with a mobile screen reader, there is no keyboard event so focus isn't trapped. In fact, TalkBack and VoiceOver don't trigger any event at all when they move focus to the next item, so there's no programmatic way to react to a user doing that.
For us, this meant a TalkBack user could move focus, including the highlighted outline, past the end of the menu to an element on the page behind the menu that wasn't visible. This is a non-equivalent and confusing experience for screen-reader users, especially for someone using the screen reader's focus highlighting to find the focused element visually on the screen. There's really no world in which it's an acceptable user experience.
Considering our audience and the technologies we expect them to use, we were able to remove the focus trap and stop covering the screen with the menu, pushing the page contents down instead. We considered using the inert attribute on the page behind the menu, but it's relatively new and many of our users may use older browser versions that don't support inert. As always, your best solution depends on your audience.
Why Does this Matter?
A disabled user is not disabled by their body. We disable users when we build products they can't perceive or use. We as an industry decide every day who is disabled by our products and who isn't.
There is nothing inherently natural about the ability to use a keyboard, mouse, and monitor to interact with a website. The information and functionality in a computer is just electrical signals. No human can perceive it or interact with it as it exists in the physical world - we all use specially-made devices like monitors and keyboards to get some benefit from it.
Most people reading this page need a keyboard to fill in a form on a web page, but we don't think of this as a disability. So why is someone else considered "disabled" when they need a voice-to-text interface to do the same? It's based on the assumptions that software builders make - that users like them are "normal."
When we build software and test it, we decide who can access it using those assumptions. We generally consider a page or feature "done" if we can perceive it and interact with it using a monitor, mouse, and keyboard. Our implicit bias tells us that anyone who can't do that must have some deficiency in their body that stops them from interacting with our software like a "normal" person can, but that's not true. We disable them when we choose to build software in a way that excludes the devices they use to interact with our software.
We as an industry have the power and responsibility to build products that work for all. We have no excuse to remain ignorant of the breadth of ways people interact with our software. So, if we truly want to build software that works for people, testing with assistive technologies is an essential, bare-minimum part of the software development lifecycle.