You often hear people say that HTML is important for good accessibility, and then say that using div and span elements to re-create HTML elements is harmful to accessibility.
At first, this doesn’t make any sense. Div and span elements are HTML after all. To find out the reason why these two statements are both true, we need to understand something of how accessibility works in the browser.
When an HTML document is loaded in the browser, a few things immediately start to happen. The browser creates a Document Object Model (DOM) that represents all the HTML elements and content in the document; it renders the HTML document so people can see it and interact with it; and, if an Assistive Technology (AT) like a screen reader or speech recognition tool is running, the browser also creates an accessibility tree that contains accessibility information about the HTML elements and content.
For each element in the HTML document, the accessibility tree typically contains the following information:
- Role: the purpose of the element;
- Name: the label for the element;
- State: the current state of the element.
If an HTML document contained this code:
The accessibility tree for that element would contain the following information:
- Role: button;
- Name: Foo;
- State: focusable.
An AT can ask the browser for the accessibility information for this particular element.
Depending on the AT, the information is then used in different ways. For example, a screen reader will use the information to tell the user they’re focused on a button called “Foo”, whereas a speech recognition user can say “Click Foo button” and the speech recognition tool will use the information to correctly locate and interact with the button.
The reason it’s possible for both the screen reader and the speech recognition tool to focus on the button, is because the browser also makes sure of it.
When we use any of the HTML interactive elements (like buttons, links, form fields, details/summary elements and so on), the browser automatically makes sure they can be used by anyone who relies on the keyboard, touch, speech recognition, and other things that are not mice.
So, when we use most HTML elements, the browser does all of this automatically. It makes the necessary accessibility information available to AT through the accessibility tree, and it makes sure that people using different input modes can use interactive elements by default.
This is where we come to the problem of using span and div elements to recreate other HTML elements. Neither element has any useful accessibility information, and neither is interactive by default.
If an HTML document contained this code:
It would effectively be ignored in the accessibility tree. The span element has no useful accessibility information to make available to AT, and it isn’t an interactive element so it can’t be focused on with the keyboard.
This is how the two statements at the start can both be true. When you use most HTML elements, the browser provides the accessibility information and mouse/keyboard/touch interaction automatically, but when you use elements like div and span the browser provides no accessibility information and no form of interaction.
You can, of course, polyfill the missing information if you need to.
The tabindex attribute can be used to make the span focusable, and the span element can be explicitly assigned a role using the role attribute:
<span id=”button” tabindex=”0″ role=”button”>Foo</span>
In accessibility terms, this pseudo-button is more or less indistinguishable from the real thing. This approach works well enough, but it comes at a cost: the code is more complex, and that complexity makes the code less robust.
The more complex the HTML element you try to recreate, the more complex your code becomes, and the greater the risk of something breaking.
So the rule of thumb is to use HTML elements with native accessibility whenever you can, polyfill missing accessibility information whenever you need to use div and span elements. Either way, make sure you test the result to make sure it works!