This article is an accompanyment to Danger! Testing Accessibility with real people
Here we take you through the steps of constructing the examples used in that article, paying particular attention to how we transform the functional html tabs with no screen reader semantics to a full-fledged tab implementation. We will make scenic stops along the way and explain the importance of what we are adding. Photo opportunities are optional.
The basic Tabs without ARIA example is an online version of the halfway point of this journey, (after step 2), whilst tabs with ARIA example is the destination.
For a better understanding of ARIA, what it is and how to use it, we recommend giving the accessibility tree: a training guide for advanced web development a spin. Then consult the ARIA authoring practices guide for advice on how to implement specific widgets. Incidentally it has a very good entry for tabs.
Our goal is to make tabs on the web behave like tabs on the desktop. We’ll use some good old fashioned HTML as the basis, then enhance it as we go. In this exercise we create a tabbed form where a user provides contact information )home, work, or other). We don’t want to overload the user with unnecessary form fields, so we let them first choose the type of contact information they wish to provide so we can present only the form fields relevant to that information.
Here is the basic HTML code for our tabs example. (the CSS code is left out but is available in either of the online examples.
<h2>My preferred contact information</h2> <ul id="tabs"> <li><a id="homeTab" href="#home" class="tab selected">Home</a></li> <li><a id="workTab" href="#work" class="tab">Work</a></li> <li><a id="otherTab" href="#other" class="tab">Other</a></li> </ul> <div id="home" class="tabcontent"> <h3>Home contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div id="work" class="tabcontent hidden"> <h3>Work contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div id="other" class="tabcontent hidden"> <h3>Other Contact Information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div>
Note how we use CSS
The only CSS understood by assistive technologies is the hidden class.
To all intents and purposes, ARIA is a screen reader only technology (though some speech recognition tools have limited support). People rely on the keyboard for many different reasons though, so getting the keyboard interaction in place is a fundamental next step.
Like tabs on the desktop, it should be possible to move focus onto the currently selected tab, cycle through the available tabs using the arrow keys, select one, then move focus from the selected tab to the panel of content that is currently displayed.
We use the tabindex attribute to handle keyboard focus. The currently selected tab has a tabindex of 0, making it focusable. The rest of the tabs have tabindex -1. If the html base element for a tab is natively focusable (such as a link( we don’t need to set tabindex="0" on the currently selected tab.
When the arrow key is pressed, we:
This method is known as roving tab index and ensures that only the active tab is in the focus order.
According to the ARIA 1.1 authoring practices guide, (that we’re working on at W3C), a tab may be selected when an arrow key moves focus to it or when the space and enter keys are pressed with focus on the tab. The difference depends on the interface and the way the content is rendered.
In either case, to ensure accessibility across devices and with various assistive technologies, onclick must be used as the trigger to select a tab, and not onfocus or any other key event. For example when an arrow key is used to select a tab, it should trigger the onclick handler for the tab that is to be selected. This ensures that a tab cannot be opened accidentally on touch screen devices, where onfocus is triggered automatically, and prevents the tabs from becoming unusable because a key press is required on a device that has no keyboard.
Moving focus to the start of a tabpanel as soon as a tab is selected is not something everyone will find helpful, especially if you decide not to implement the keyboard handling we mention above. What if someone selects the wrong tab, or decides the tab wasn’t the one they wanted? You’ve made an assumption about what that person wanted to do, and with rare exceptions we’re not fond of people making those sort of assumptions on our behalf.
You can view the JQuery code that handles the keyboard interaction on the "Tabs with ARIA" example page linked to above.
Once the basic interaction has been tested with mouse, keyboard and touch, it’s time to add some ARIA to enhance the experience for screen reader users.
Now let us add the required ARIA roles to our content.
<h2>My preferred contact information</h2> <ul id="tabs" role=”tablist”> <li role=”presentation”><a id="homeTab" href="#home" class="tab selected" role=”tab”>Home</a></li> <li role=”presentation”><a id="workTab" href="#work" class="tab" tabindex="-1" role=”tab”>Work</a></li> <li role=”presentation”><a id="otherTab" href="#other" class="tab" tabindex="-1" role=”tab”>Other</a></li> </ul> <div id="home" class="tabcontent" role=”tabpanel”> <h3>Home contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div id="work" class="tabcontent hidden" role=”tabpanel”> <h3>Work contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div id="other" class="tabcontent hidden" role=”tabpanel”> <h3>Other Contact Information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div>
Finally, let’s add the ARIA attributes that provide important context info for screen readers:
<h2>My preferred contact information</h2> <ul role="tablist" id="tabs"> <li role="presentation"><a role="tab" aria-selected="true" aria-controls="home" id="homeTab" href="#home" class="tab selected">Home</a></li> <li role="presentation"><a role="tab" aria-selected="false" aria-controls="work" id="workTab" href="#work" class="tab" tabindex="-1">Work</a></li> <li role="presentation"><a role="tab" aria-selected="false" aria-controls="other" id="otherTab" href="#other" class="tab" tabindex="-1">Other</a></li> </ul> <div role="tabpanel" aria-labelledby="homeTab" id="home" class="tabcontent"> <h3>Home contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div role="tabpanel" aria-labelledby="workTab" id="work" class="tabcontent hidden"> <h3>Work contact information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div> <div role="tabpanel" aria-labelledby="otherTab" id="other" class="tabcontent hidden"> <h3>Other Contact Information</h3> <p>Lots of input fields that do not matter for the purposes of demonstrating tabs.</p> </div>
And we have arrived at our destination, "tab widget city". A couple of years ago we would have said that the place is a bit of a mess, with inconsistent implementation and assistive technology support making it unreliable and confusing for the user. Today we can confidently say it is a more accessible place with the ARIA markup. But there is still room for improvements, both in terms of the authoring consistency and how assistive technologies take advantage of that markup.
Accessibility requires a lot of players to do their part but without the necessary semantic information that ARIA provides we never give user agents a chance to create a better world for those who need to access web content in an alternative and creative fashion.