After studying web accessibility for the past few months, I’ve learned more about accessibility than I ever imagined. Through the Deque University courses, I went over topics like testing with screen readers, WCAG 2.0, ATAG, and Web Accessibility Initiative – Accessible Rich Internet Application (WAI-ARIA). The W3C defines WAI-ARIA as “a way to make Web content and Web applications more accessible to people with disabilities.” However, when reading over material for WAI-ARIA, I noticed that there are many ways to implement it incorrectly, and you can actually make a website worse for people with disabilities!
In this article, I’ll go over a few things that you should avoid when using WAI-ARIA.
Forgetting to Use Native HTML Elements
What to Avoid
You should avoid repurposing HTML elements when other native elements already have the behavior you need. For example, a developer may think that the <div>
element is easier to style than a native <button>
element. The downside to using a <div>
is that in order to make the <div>
behave like a native <button>
element, they will need to add additional markup and JavaScript for event handlers.
In this code example taken from Twitter, they are using a <div>
with an ARIA button role:
<div aria-label="Top Tweets on" role="button" data-focusable="true" tabindex="0">...</div>
Since <div>
elements aren’t focusable by default like a <button>
element, they also needed to add tabindex=“0″
to allow the <div>
to receive focus.
What to Do
Here’s an example using the native <button>
element:
<button aria-label="Top Tweets on">...</button>
The <button>
element has the button role by default and is focusable by default. The first example is accessible, but it’s better to use the button element since it already has built-in functionality to save on development time.
The YouTube channel for Google Chrome developers has a helpful video on using button elements instead of divs or spans.
Adding Redundant Roles to Elements
If you’re already using a semantic HTML element like a button, you don’t need to add an ARIA role=“button”
on top of it. The native <button>
element has implicit ARIA semantics, which means the browser already sets the role to button.
What to Avoid
Avoid the following examples:
<button role="button">Cancel</button>
<h1 role="header">ARIA is great</h1>
Adding an extra ARIA role is not recommended and will not add any benefit.
What to Do
Not adding these redundant roles will save on development time.
<button>Cancel</button>
<h1>ARIA is great</h1>
For more information on this topic, SitePoint has a great article about avoiding redundancy with WAI-ARIA.
Inadvertently Overriding Semantics
What to Avoid
One of the second rules of ARIA from the “Using ARIA Document” says, “Do not change native semantics, unless you really have to.” When you’re using semantic HTML, it is possible to add an ARIA rule to override the original meaning of the element.
<h1 role="button">A heading</h1>
What to Do
If you want to change a heading into a button, it would be best to do this:
<h1><button>A heading</button></h1>
Using aria-hidden
Inappropriately
What to Avoid
While there are good use cases for hiding elements or web functionality from a screen reader, use care when doing this. When using aria-hidden=“true”
on an element, make sure it is not a focusable element. For example, using aria-hidden=“true”
on a button will remove it from the accessibility tree, but it will still be focusable by keyboard. When a screen reader user is using their keyboard to tab through focusable content, they will reach the button, but will not hear the text announced inside the button. This experience can be confusing for users if they tabbed to an element that does not announce anything.
<button aria-hidden="true">Button text</button>
What to Do
To fix this issue, you can add tabindex=“-1″
to remove the button from tab order. Since the button below is not focusable because it’s using tabindex=“-1″
, it’s now appropriate to have aria-hidden=“true”
. The screen reader will not focus on this element and the user will be able to focus on the next interactive element on the page.
<button tabindex="-1" aria-hidden="true">Button text</button>
Using aria-live
Inappropriately
When parts of the page content update dynamically, it’s best practice to let a screen reader user know about these changes. By using JavaScript, you can insert text into an aria-live
container that will announce changes to screen reader users.
What to Avoid
If you’re going to use aria-live
, do not add it to the body tag.
<body aria-live="assertive">
Every single change that happens within the <body>
will be read by the screen reader and will interrupt the user.
What to Do
Instead, use aria-live
on elements that contain changes you want to announce.
<div aria-live="polite"><!-- announcement updates here --></div>
To help you better understand aria-live
, Deque University has a useful aria-live
playground, where you can customize the configurations to create different live regions.
Adding Form Instructions Only in an aria-label
What to Avoid
When developing a form, instructions need to be understood by sighted users and screen reader users. In the example below, the instructions for setting a new password will only be accessible for screen reader users. Sighted users will not see the content inside of aria-label
and will not know the rules for creating a new password.
<form>
<label for="new-password">New password:</label>
<input type="password" id="new-password"
aria-label="Your new password must be a minimum of 10 characters with at least one lowercase, one uppercase, one numeral, and one special character.">
</form>
What to Do
In this example, sighted and screen reader users can both understand the instructions for the password field:
<form>
<p id="password-instructions">Your new password must be a minimum of 10 characters with at least one lowercase, one uppercase, one numeral, and one special character.</p>
<label for="new-password">New password:</label>
<input type="password" id="new-password" aria-describedby="password-instructions">
</form>
The password input is using the aria-describedby
attribute to associate with the paragraph’s attribute of id=“password-instructions”
. Then aria-describedby
will provide screen readers with instructions for creating a new password when the user is focused on the password input field.
Forgetting to Set Parent Roles
It’s important to note that when using ARIA roles, some roles must be contained by a parent role. In the instance of setting up tabs, you must set the parent role of “tablist” since it’s the required context for the “tab” role. Elements that are missing the required parent role will not accurately convey relationships to assistive technology.
What to Avoid
Here’s an example where the parent role is missing:
<ul>
<li role="tab">Dogs</li>
<li role="tab">Cats</li>
</ul>
What to Do
Here’s an example with the parent role correctly included:
<ul role="tablist">
<li role="tab">Dogs</li>
<li role="tab">Cats</li>
</ul>
Forgetting to Set Children Roles
It’s just as important to make sure the children roles are set for any existing parent roles.
What to Avoid
In this example, the role “tab” is owned by the “tablist” role as a required owned element.
<ul role="tablist">
<li>Dogs</li>
<li>Cats</li>
</ul>
What to Do
Here’s the correct way:
<ul role="tablist">
<li role="tab">Dogs</li>
<li role="tab">Cats</li>
<ul>
Use ARIA Wisely
While using ARIA roles, states, and attributes can make websites more accessible, it is easy to make things worse if we use them incorrectly. Knowing the guidelines is important, but you can also find issues with ARIA in your code with free tools like the aXe extension for Chrome and Firefox or Lighthouse in Chrome Dev Tools.