Label the Rest of the Things!
Native accessible name properties that we discussed in part 1 are all great, but there are situations where these don’t suffice - where either no method for providing an accessible name exists in HTML5 or a situation arises where standard HTML5 methods aren’t enough. Enter aria-label and aria-labelledby. Aria-label and aria-labelledby are global WAI-ARIA attributes which means they can be used on all HTML5 elements although they have widest support by screen readers when used on focusable elements. Let’s look at some use cases.
Multiple nav elements with aria-label
What happens when you have multiple navigation blocks on a page using the <nav> element where it’s clear to a sighted user what each menu is but there are no indicators such as headings for each menu for a blind user? For example, a site with a main menu, a user menu, a footer menu? Mark up the menus with just the <nav> element and a screen reader user doesn’t know what distinguishes the different menus from each other without listening to the menu links. If they bring up a list of the page's landmarks, they’ll just hear:
This is a great use for aria-label:
<nav aria-label="Main menu"> … list of links </nav> <nav aria-label="User menu"> … list of links </nav> <nav aria-label="Footer menu"> … list of links </nav>
Now if the user brings up a list of landmarks, they’ll hear:
Main menu navigation
User menu navigation
Footer menu navigation
Much more helpful!
Search textbox without <label> using aria-label
Or say you have the common situation of a search form in the header of the site with just a search box and no visible label. You could include the label and visibly hide it or you could use aria-label to provide a label for the input:
<input id="searchbox" type="text" name="searchbox" aria-label="Search this site">
This way, the screen reader will read “Search this site, edit text” (or similar, depending on screen reader) instead of just a generic “edit text” or “input” which is rather unhelpful.
Textboxes with aria-labelledby
Sometimes there is a label available for an element but just no relationship established between the two. Consider the following form:
Visually, it’s pretty self-explanatory what should go in each textbox. But without visual context, it’s unclear what content is expected because there are no form labels. A screen reader user would simply hear a series of “edit text, edit text, edit text” which tells them there are textboxes for input. However, we do have column and row headers that we can use to label each textbox. Using aria-labelledby, we can specify the header or headers that should label each input.
<form> <table> <caption>Pets</caption> <tbody> <tr> <th id="petnumber" scope="col">Pet's Number</th> <th id="petname" scope="col">Pet's Name</th> <th id="species" scope="col">Species</th> <th id="age" scope="col">Age</th> </tr> <tr> <th id="pet1" scope="col">Pet 1</th> <td><input type="text" name="pet1name" aria-labelledby="pet1 petname"></td> <td><input type="text" name="pet1species" aria-labelledby="pet1 species"></td> <td><input type="text" name="pet1age" aria-labelledby="pet1 age"></td> </tr> <tr> <th id="pet2" scope="col">Pet 2</th> <td><input type="text" name="pet2name" aria-labelledby="pet2 petname"></td> <td><input type="text" name="pet2species" aria-labelledby="pet2 species"></td> <td><input type="text" name="pet2age" aria-labelledby="pet2 age"></td> </tr> <tr> <th id="pet3" scope="col">Pet 3</th> <td><input type="text" name="pet3name" aria-labelledby="pet3 petname"></td> <td><input type="text" name="pet3species" aria-labelledby="pet3 species"></td> <td><input type="text" name="pet3age" aria-labelledby="pet3 age"></td> </tr> </tbody> </table> </form>
Now a screen reader user will hear:
Pet 1, Pet’s Name, edit text
Pet 1, Species, edit text
Pet 1, Age, edit text
Pet 2, Pet’s Name, edit text
Pet 2, Species, edit text
...and so on.
This will tell the user exactly what piece of information is needed and for which pet.
Navigation elements with aria-labelledby
Taking our navigation example from above, what if we do have headings for our navigation menus? No need to add duplicate labels. We can reuse them and associate the headings with the menus so that the name of the navigation menu is read along with the navigation element:
<h2 id=”popularposts”>Popular Posts</h2> <nav aria-labelledby=”popularposts”> <ul> <li><a href="/blog/drupal-agency-mediacurrent-awarded-best-overall-smb-salesforce"> Drupal Agency, Mediacurrent, Awarded Best Overall SMB by Salesforce</a></li> ….more link list items </ul> </nav>
Now, instead of just navigation, the menu will be read as "Popular Posts navigation."
Although not a naming mechanism, aria-describedby is a close relative to aria-label and aria-labelledby. It allows you to associate existing additional information to your element. For instance, say you have a text field that has a label but requires the user to be aware of additional information in order to fill it in. Putting that additional information in the label field could make it very long. So, it’s generally added before or after the text field in a paragraph or div tag like so:
This means that the additional instructions won’t be read to the user in forms mode - when the user is tabbing from input to input. It will be skipped. Aria-describedby is the way to make sure these additional instructions are made known to the user:
<label for="telephone">Telephone number</label> <input type="text" id="telephone" name="telephone" aria-describedby="telephoneformat" /> <p id="telephoneformat">Please use the format 123.555.1234</p>
Now, when focus is placed on the Telephone number input, the label will be read along with the paragraph that includes instructions for the format. Note, however, that on VoiceOver, there is a 7 second delay before aria-describedby text is read. Why? ¯\\_(ツ)_/¯
As you can see, these 3 simple WAI-ARIA attributes can come in pretty handy and go a long way in making a page more accessible to screen reader users. Using native HTML accessible names is the way to go when possible, and when they’re not available, we have aria-label, aria-labelledby, and aria-describedby to fall back on.