From HTML to ARIA Tabs, A Travelog

Tabs – a 3-step journey from HTML to ARIA

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 where we 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, which 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.

Step 1: The basic HTML

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.

Note, due to formatting differences, section elements are used instead of div elements as seen within the live examples. Please use the live examples by saving them locally to run the code, since this will prevent any special character markup from clogging the works.

 

<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>

<section 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>
</section>

<section 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>
</section>

<section 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>
</section>

 

Note how we use CSS

  • To make links visually look like tabs.
  • To visually indicate which tab is selected
  • To display tabpanel content
  • To hide inactive tabs.

The only CSS understood by assistive technologies is the hidden class.

Step 2: Add the desired keyboard functionality.

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:

  • Make the newly selected tab focusable (adding tabindex of 0 or removing tabindex=”-1″ if the element is natively focusable.
  • Take the old tab out of focus order (by adding tabindex of -1).

This method is known as roving tab index and ensures that only the active tab is in the focus order.

Important notes on tab selection.

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.

Yes, but what about the ARIA?

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.

Step 3: Add required ARIA roles.

Now let us add the required ARIA roles to our content.

  1. Add role=”tablist” to the <ul> container that holds all the tabs. This tells assistive technologies that a set of tabs is coming up and allows them to respond in the way most beneficial to the user. Screen readers, for instance can switch from browse mode into interactive or forms mode, which passes the keyboard events directly to the webpage instead of intercepting them.
  2. Add role=”tab” to each of the <a> elements that represent those tabs. This is what tells the screen reader to forget the HTML consists of a list of links, and instead tell the user it’s a set of tabs. Make sure to always add role=”tab” on the element that has the onclick Javascript event.
  3. Add role=”presentation” to each of the <li> elements. We need to use the <li> elements so the underlying HTML structure is usable on older devices (that don’t support ARIA), but the presentation role is what stops screen readers that do support ARIA from announcing the list items and enables them to calculate and announce the number of tabs in the tablist along with the relative position of the selected tab (e.g. “tab 2 of 3” for the work tab in our example.
  4. Add role=”tabpanel” to the <section> containers. This enables the screen reader to announce the beginning and the end of the visible tabpanel 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>

<section 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>
</section>

<section 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>
</section>

<section 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>
</section>

 

Step 4 (final step): Adding the ARIA attributes.

Finally, let’s add theARIA attributes that provide important context info for screen readers:

  1. Add the aria-controls attribute to each tab element. Its value is the id of the tabpanel whose display state is controlled by the tab. This attribute provides a programmatic context between the tab and its associated tabpanel. This programmatic context is important, and has already been turned into a keyboard shortcut (JawsKey-alt-m) using Jaws and Firefox. We expect more user agents to implement similar functionality.
  2. Add the attribute aria-labelledby to each tabpanel element. Its value is the ID of the tab that controls it. This is the reverse of the relationship explained in the above step and could also be used by assistive technologies, e.g. to provide a keyboard shortcut from the tabpanel to its associated tab.
  3. Add aria-selected=”true” to the currently selected tab and aria-selected=”false” to tabs that are not selected. Note how we used a CSS class to do the same visually? This is important, because screen reader user can see which tab is selected without switching to forms mode. Most screen readers automatically switch to forms or application mode when screen reader focus hits a tablist (to pass the keyboard keys directly to the page) , but advanced screen reader users often choose to override this behaviour.
  4. (optional) add aria-orientation to the tablist to indicate the direction (vertical or horizontal) of the visual tab layout. This can also indicate which set of arrow keys (up down, or left/right) to use for selecting tabs. Keep in mind that if the associated tabpanel has a lot of content, sighted keyboard only users may want to use the arrow keys up and down to scroll the page, so a horizontal set of tabs with right/left arrow keys might provide a better experience for that user group.

 

<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>

<section 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>
</section>

<section 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>
</section>

<section 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>
</section>

 

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.

Also, don’t forget that you can use Visual ARIA to visually display ARIA usage during development to aid in this process.

Co-authors: Birkir Gunnarsson from Deque Systems, Bryan Garaventa from SSB BART Group, Lèonie Watson from The Paciello Group (TPG), and Matt King from Facebook.

 

Advertisements