ARIA is a great way to make things technically accessible, sometimes without requiring markup changes. But it can be tricky, even if you’re using it in a technically correct way. In this post, Jeff breaks down an ARIA tabs interaction to see how ARIA can impact users with disabilities—and how to make tabs truly accessible.

At Simply Accessible, we believe strongly in including people with disabilities in our usability studies. We test both code and design prototypes as well as web pages in production, and it’s incredibly important for us to see how our users interact with our clients’ sites. It’s difficult to predict how different types of users will experience a given interaction. The results of usability testing can sometimes be quite surprising.

ARIA tabs are one of those surprises.

ARIA is a great way to make things technically accessible, sometimes without requiring markup changes. But ARIA is tricky, even if you’re using it in a technically correct way. At some point, the theory breaks down in practice, and users get stuck in the middle of an interaction. In this post, we’ll build an interaction from the ground up to understand why this can be a challenge for people. Sometimes, a widget or interaction that’s technically accessible…isn’t.

A brief introduction to ARIA tabs

Tabbed interfaces are one of the more common interactions we see on many websites. Tabs and tab panels serve as an excellent way of grouping content together and presenting it in digestible chunks for our users.

But, when we’re working with ARIA tabs, sometimes even textbook-perfect tabbed content can cause serious challenges for some users. First, let’s build some tabs, starting with good old HTML.

The basic markup for tabs starts out simple and clean. This provides a good semantic base:


<div id="tabs">
    <ul class="tabsList">
        <li><a href="#ipa" id="tab-ipa">India Pale Ale (IPA)</a></li>
        <li><a href="#gueuze" id="tab-gueuze">Gueuze</a></li>
        <li><a href="#imperial-stout" id="tab-imperial-stout">Imperial Stout</a></li>
    </ul>
    <div class="tabPanel">
        <h2 id="ipa">India Pale Ale (IPA)</h2>
        ...
    </div>
    <div class="tabPanel">
        <h2 id="gueuze">Gueuze</h2>
        ...
    </div>
    <div class="tabPanel">
        <h2 id="imperial-stout">Imperial Stout</h2>
        ...
    </div>
</div>

Next, with progressive enhancement, we’ll layer on some extra attributes and ARIA roles, and use JavaScript to provide:

  • a programmatic connection between our list of tabs and the tab panels; and
  • a programmatic indication of the state of each tab panel—hidden vs. visible.

Ideally, both of these additions will help users of assistive technology successfully interact with our tabs:


<div id="tabs">
    <ul class="tabsList" role="tablist">
        <li role="presentation" class="current"><a href="#ipa" id="tab-ipa" role="tab" aria-selected="true" tabindex="0">India Pale Ale (IPA)</a></li>
        <li role="presentation"><a href="#gueuze" id="tab-gueuze" role="tab" aria-selected="false" tabindex="-1">Gueuze</a></li>
        <li role="presentation"><a href="#imperial-stout" id="tab-imperial-stout" role="tab" aria-selected="false" tabindex="-1">Imperial Stout</a></li>
    </ul>
    <div class="tabPanel" role="tabpanel" aria-hidden="false" aria-labelledby="tab-ipa" style="display: block;">
        <h2 id="ipa">India Pale Ale (IPA)</h2>
        ...
    </div>
    <div class="tabPanel" role="tabpanel" aria-hidden="true" aria-labelledby="tab-gueuze" style="display: none;">
        <h2 id="gueuze">Gueuze</h2>
        ...
    </div>
    <div class="tabPanel" role="tabpanel" aria-hidden="true" aria-labelledby="tab-imperial-stout" style="display: none;">
        <h2 id="imperial-stout">Imperial Stout</h2>
        ...
    </div>
</div>

ARIA tabs consist of a role="tablist" element, which has some some role="tab" elements. These tabs are then linked to role="tabpanel" elements that contain the corresponding content for each tab. Our JavaScript handles the visual toggling of tabpanel elements via CSS as well as programmatically with aria-hidden="true" when a user interacts with the tabs.

Following guidance from the WAI-ARIA 1.0 Authoring Practices for the Tab Panel Widget, we’ll also supply keyboard behaviour for our ARIA tabs. These interactions have some notable differences from what we would usually expect from a list of links:

  • Only the current, active tab is in the tab order of the page. We’ll remove inactive tabs from the tab order by applying tabindex="-1".
  • When focus is within the list of tabs, using the arrow keys on the keyboard, a user is able to navigate and activate the other tabs in the list.

See the full example Standard ARIA tabs by Jeff Smith (@jeffsmith) on CodePen.

The programmatic thinking behind this set of tabs is rock solid. This implementation should provide all our users with a great experience, right?

Well, maybe not…

What real users experience

We’ve tested a few different ARIA tab implementations in our usability sessions with real users. We were incredibly surprised with what participants experienced.

Some of the non-visual users in our studies used the links list functionality in their screen reader software. When they did, the links with role="tab" within the role="tablist" element didn’t show up in the list. These elements have moved to a list of ARIA elements—a relatively new piece of functionality in screen readers, and one that some folks weren’t familiar with. So, these users weren’t able to find any of the content contained in the inactive tabs.

Also, many sighted keyboard users were frustrated when the ability to tab to each individual tab was removed through the use of tabindex="-1". People often weren’t aware of the arrow key shortcuts that replace the tabbing interaction they’d normally use to move between links/interactive elements. This includes people who use magnification tools with their screen reader (like ZoomText).

The arrow key shortcuts also impact screen reader users. These users have to use a pass through modifier key (ie. the alt key) to activate each tab, which bypasses the native screen reader arrow key behaviour (reading line by line, word by word, or character by character) and instead passes the keystroke directly through to the page.

Even though they could see that the tabs existed, some people weren’t able to figure out they needed to use the arrow keys to toggle the inactive tabs, so they couldn’t access that content.

Quite often there is critical information or functionality contained within tabs. With so many groups of users unable to navigate the interaction, these tabs now represent  a pretty significant barrier for task completion.

So what can we do about it?

We’re in luck! A few small changes to our initial example will make a huge difference for our users.

To begin, let’s remove the role="tablist", role="tab", and role="tabpanel" attributes from our script. This will prevent screen readers from removing these elements from the standard element lists that many people rely upon.

Next, let’s remove tabindex="-1" from the links that serve as tabs to improve the experience for keyboard users by restoring the tabbing behaviour they’re used to with links.


<div id="tabs">
    <ul class="tabsList">
        <li class="current"><a href="#ipa" id="tab-ipa" aria-selected="true">India Pale Ale (IPA)</a></li>
        <li><a href="#gueuze" id="tab-gueuze" aria-selected="false">Gueuze</a></li>
        <li><a href="#imperial-stout" id="tab-imperial-stout" aria-selected="false">Imperial Stout</a></li>
    </ul>
    <div class="tabPanel" aria-hidden="false" aria-labelledby="tab-ipa" style="display: block;">
        <h2 id="ipa">India Pale Ale (IPA)</h2>
        ...
    </div>
    <div class="tabPanel" aria-hidden="true" aria-labelledby="tab-gueuze" style="display: none;">
        <h2 id="gueuze">Gueuze</h2>
        ...
    </div>
    <div class="tabPanel" aria-hidden="true" aria-labelledby="tab-imperial-stout" style="display: none;">
        <h2 id="imperial-stout">Imperial Stout</h2>
        ...
    </div>
</div>

The final piece of the puzzle is focus management.

Since we’re removing tabindex="-1" from inactive tabs, we don’t want users to be forced to navigate through all the inactive tabs just to get to the newly revealed content. Instead, when a user activates a tab, we should place the focus on the first heading contained within the revealed tab’s content using JavaScript.


// Where var tabpanel is our revealed tab content
tabPanel.children("h2").attr("tabindex", -1).focus();

So, wait. We’ve removed ARIA roles from our code, and we’ve actually made these tabs more useful for our users? In this case, we have indeed. People navigating the tabs with a screen reader will no longer hear that they’re navigating tabs. But, now they’ll be able to locate and access the content that they expect, and need, to find.

See the full example Standard tabs without ARIA roles by Jeff Smith (@jeffsmith) on CodePen.

The best approach to fixing most interaction problems is to start out by solving as much as you can via plain old HTML and JavaScript. If there are gaps remaining, ARIA can provide a great help in filling those gaps, but it’s incredibly important to test these solutions with real people.

What other accessibility techniques have you come across where the technical solution doesn’t always yield the best user experience? How did you resolve the issue, and maybe more importantly, what best practices did you discover to help us all improve? Share in the comments below!

25 thoughts on “Danger! ARIA tabs”

Read comments

  1. Very interesting.

    And what use will have the tab and tablist roles in the future, then?

    1. Jeff Smith says:

      Vincent, I believe that at some point ARIA tabs will work as intended for users. We need to keep testing to be sure what we’re building is working for our users. Perhaps by that time there’ll be a new method for presenting tabs that will exceed what we have now.

  2. Good read, thanks.

    I’m curious to know what you think about using a different HTML structure to make things simpler? A structure that would not require using ARIA to help people make sense of the markup?
    Something like this for example:
    http://codepen.io/thierry/pen/gPoWxj

    1. Jeff Smith says:

      I think it would absolutely be worthwhile doing some user testing on this approach. However, I’d be hesitant to use radio buttons for a purpose they’re not necessarily intended (toggling content). It’s a different interaction design that users may not expect. Perhaps it’ll work out spectacularly though, the only way to know is to test with people. 🙂

  3. Nico says:

    Imho, the ARIA role in the first example are set up in a “logical way”, but in practical, it should be a little different. In my tab script http://a11y.nicolas-hoffmann.net/tabs/ the list of links is transformed differently (I keep only relevant information):

    ul role=”tablist”
    li role=”presentation”
    a aria-selected=”false” tabindex=”-1″ aria-controls=”blabla” role=”tab” id=”…”

    etc.

    with this way, for example, NVDA announces the number of tabs.

    Anyway, this is a “problem” : always have to test, test, test, test, even if you respect the Design Patterns, etc. 🙂

    1. Jeff Smith says:

      Life would indeed be grand if we only had to deal with NVDA. 🙂

      Beyond the issue of ARIA roles, there are other bits that we have to consider as I mentioned. Sighted keyboard users are another group of people that really struggled with this interaction due to tabindex=”-1″ being added to inactive tabs. This really through people off as they expected to be able to use the tab key on their keyboard to navigate through the list of tabs.

      1. Nico says:

        > Life would indeed be grand if we only had to deal with NVDA.

        Oh yes. (sigh, thinking to VoiceOver and Jaws strange issues sometimes…)

        > Beyond the issue of ARIA roles, there are other bits that we have to consider as I mentioned […]

        Ok, I didn’t catch up, now I’ve understood (sorry, my mistake). That makes me wondering something about my plugin and I would like to have your mind:

        – I could add a kind of help (only visible to keyboard/vocal) explaining how it works ?
        – or I could provide a mode to activate tab navigation ?

        Anyway, no perfect solution in any case.

  4. Peter Hentges says:

    You mentioned “Some of the non-visual users in our studies used the links list functionality in their screen reader software” and so missed the ARIA roles. Did you consider removing the links with role=”tab” from an HTML list? That is using a markup like:

    India Pale Ale (IPA)

    1. Jeff Smith says:

      Hi Peter. What would be the intent of removing the links from the unordered list? The bonus of using a list to contain the tab links is that users of assistive technology can hear how many links/tabs there are.

      1. Peter Hentges says:

        I agree about the benefit. I have seen it argued (by people using assistive tech) that having navigation-type links in lists results in redundant speech. It probably requires broader survey of actual users to find preferred modes of operation.

        But it sounded like the issue you encountered was that users used their assistive tech to search for a list, and not finding one were unable to access the tabs. If the tab links were not in a list to begin with, would this have been an issue? (Just thinking of other ways to approach the problem, rather than assuming the markup is fixed.)

      2. Jeff Smith says:

        The list I was referring to was the “links list” functionality available in screen readers. It pulls a list of all of the available links from the page and allows the user to search/navigate the page via the links. There are similar functions available for headings, landmarks, etc.

      3. Peter Hentges says:

        Ah-ha! I misinterpreted. So it was an issue of expectation of the user (the tabs would be in the “links list”) vs. the software implementation (the tabs are in an “ARIA elements list”).

        Sounds like the problem is very similar to what web developers had to deal with for browser-specific implementations of features back in the bad old days. We eventually settled (as an industry) on coding to standards and forcing the browser manufacturers to comply to the standard. The difficulty you’re describing is that doing something similar here doesn’t just end up with a degraded experience, it ends up with a user being wholly unable to access content. Much trickier.

    2. Nico says:

      We had the same kind of problem with a version of Jaws (even if we set up the role=”tab” on the a in our tab example, in the link provided in another comment).

      We simply removed the href attribute, and it seemed to be ok. Don’t know if it would be the same for a different structure as provided in this example.

      1. Peter Hentges says:

        What I’ve run into in my work is that removing the href attribute effectively removes the ability to access the control via keyboard. (At least without including a tabindex value.) It also would remove the native functionality of tabbed content (triggering the link would jump to the associated content) if JavaScript or CSS were disabled for any reason.

  5. Marty Nelson says:

    We need a “caniuse” for ARIA, along with “polyfills and fixes” for closing gaps.

  6. Hi,
    I appreciate the difficulties, especially regarding the adoption of new technologies and how people perceive them, however I don’t think it’s beneficial to throw the baby out with the bathwater like this.

    Many of the issues that are discussed here include lack of sufficient training by the end user, which I agree is a problem but not necessarily one that requires complete recoding by all web developers. If an AT for instance provide sufficient behaviors and features that enable reliable access to such components, then it becomes a training issue for the AT vender to properly convey this to end users so they can take advantage of these new features and controls.

    Regarding the sighted keyboard users inability to understand the programmed functionality, this can be addressed using a CSS pseudo element that appears when the role=”tab” element receives focus through a[role=”tab”]:focus:after pseudo element for example to show a double arrow icon to visually indicate the desired keyboard movement. This would be a visual indicator of the correct keyboard functionality to expect when a Tab has focus.

    Regarding the inability to actually activate ARIA tabs, I’ve been building these components for years and have not noticed this. Can you reproduce this at the following page?
    http://whatsock.com/bootstrap/jquery/

    All of the controls that switch the view panes are constructed of ARIA Tab controls in strict accordance with the ARIA spec, as documented in the matrices table at
    http://whatsock.com/training/matrices/#tablist

    I do agree that not all browsers and AT combinations support this in the exact same manner across the board, but we must do what we can to program compliant constructs in order to allow such technologies to converge on reliable interactions by actually building such components correctly.

    All the best,
    Bryan Garaventa

  7. As I understand it, the WAI’s recommended interaction and tab flow stems from the way people using AT would tab through traditional desktop interfaces (e.g. Windows). I wonder if, as more people use the Web as their primary means of interacting with software, those mappings have become less relevant, either through loss of muscle memory in the case of long-time AT users or a lack of awareness for those who’ve only used AT since the advent of the Web and Web-based interactions (i.e. folks who’ve never had to navigate their way through complex interfaces like Windows’ Device Manager).

  8. Matt King says:

    As a blind user and accessibility engineer, I understand the frustration with ARIA and how it feels as quirky as cross-browser support in the 90s. So, there is a level of practicality to this post that is appealing.

    At the same time, we need to be careful about how we interpret user testing in the accessibility arena. What if it were 1995 and you were testing Windows products with people with disabilities? You might have arrived at the conclusion that the Windows developer should make their products feel more like a DOS product in order to get positive outcomes in user testing.

    We are in the midst of a similar paradigm shift today. Instead of web pages having to be documents that serve an endless tab sequence of links, the web has become a platform for GUI development. It has provided much needed usability for most people, but people with disabilities have been left behind. As your testing proves, most still think in web 1.0 terms. Those terms prevent the usability gains that others are already experiencing.

    So, the challenge is how to make the paradigm shift that is needed so that people with disabilities can get as much benefit from the web as others but to do so with the least amount of pain possible. The pain of the 90s was pretty severe for lots of people. The pain of trying to hold on to the 80s would have been worse.

    Rather than avoiding tabs completely, I recommend finding creative solutions to resolving end user difficulties that are consistent with both the ARIA specification and best practice. The technique for providing visual clues to keyboard users that Bryan mentioned above is a perfect example of that kind of thinking.

    Note that the ARIA Authoring Practices guide that is referenced here is still a draft. Unfortunately, the ARIA 1.0 guide was never completed. The lack of authoritative reference implementations has made consistency among assistive technologies difficult. An ARIA 1.1 guide is underway and will be completed with the specification.

    Anyone who wishes to help move accessibility forward is welcome to provide feedback on the authoring practices or even contribute. See the current working draft with info on how to do this at:
    http://w3c.github.io/aria/practices/aria-practices.html

  9. Birkir Gunnarsson says:

    Hi
    A few things:
    1. I posted a reply to this thread on 04/15, that comment never got past moderation, why?
    2. There are a couple of minor ARIA markup problems here, not fundamental, but both are important for usability reasons, both are mentioned in the ARIA spec and Authoring Practices Guidelines:
    2.1. There is no aria-controls relationship between the tabs and their tabpanels (tab has aria-control attribute whose value is the id of its tabpanel).
    This relationship opens up possibilities for screen readers and other a.t. to provide custom keyboard shortcuts to move between tabs and tabpanels, even if author failed to provide one. See Jaws + Firefox where Jaws Key – alt – m moves to controlled element (sadly implementation of other combinations is still behind, but it has got potential).
    The spec does not say this is a must, but does recommend it in addition to the inverse ria-labelledby relationship.
    2.2 aria-selected is used on links in you solution demo. The aria-selected attribute is not permitted on links and is therefore not announced. We have added a new attribute in ARIA 1.1 to address this scenario, aria-active.
    3. A tab is not a link.
    User expects a link to navigate to another place on the webpage, or to another webpage.
    The user does not expect that activating a link will display and hide parts of the page.
    Therefore treating tabs as links can create significant confusion, and a link is not the most natural way for screen readers to present this construct.
    Jaws maps a tablist to a combobox (same as select), which makes sense given the behavior and keyboard. Voiceover on OSX maps it to radiobuttons. It is true that the spec should give clearer guidance to ensure a more uniform support, to help end users learn the new paradigm.

    Your proposed solution did not change the novel behavior that you are describing in any way, it just removed the ARIA markup used to show user that this is not your grandmas set of links, it is an interactive widget that the user eventually has to learn.

    So while I totally agree with your premise, we need to be mindful of our end users and not get lost in our own constructs and inventions, we also cannot solve issues by hiding them or remapping elements used for other things to present the new widgets as well.
    There is no ultimate answer in accessibility, and technology is evolving so fast that even if we had one today it would be wrong in a year. Our job is to make sure all users will enjoy the benefit of new ideas and inventions as much as possible.
    I hope you find this reply helpful, it is a good post and provokes good thinking about what it is that we do, and reminds us who we are doing it for.
    Thanks, and I hope this reply gets posted.
    -Birkir

    1. Hi Birkir — we didn’t see a comment come through on April 15th, and I don’t see anything flagged for moderation/spam in the comment queue. So, unfortunately, I can’t answer your question other than to say I can’t answer your question 🙂

      Regarding aria-controls — we’re aware of aria-controls and its use, but it hasn’t made its way into any of the tabs implementations that we’ve seen in the real world that we’ve done testing on. It will provide additional programmatic relationships that assistive technologies can take advantage of in the future. And as I mentioned in my previous comment on the follow up article, the aria-selected on the link was leftover from the original where the link had a role=tab on it.

      Yes, this is important conversation to have. I’m not sure I agree with you that a tab is not a link. We have created tabbed interfaces for years, long before ARIA. In a non-ARIA world, clicking on an in page link simply sends a person to another part of the page. The fact that the content in the tab happens to be in another location on the page actually makes it perfect for setting that expectation. Click that link, it takes you to that content. In the absence of JavaScript, it takes you there like an old school href. With JavaScript, it just happens to show what was previously hidden, and then move the focus there.

      There’s lots more here to discuss, but I’ll finish with this one item. You wrote “Our job is to make sure all users will enjoy the benefit of new ideas and inventions as much as possible.” Yes, but our job is just as much to make sure that users will enjoy the benefit of, and be able to use, the things we already have. The work that we did showed us very clearly that people other than web professionals aren’t necessarily ready for all the things that we’re inventing.

  10. Matt King says:

    Derek, you wrote:

    “The work that we did showed us very clearly that people other than web professionals aren’t necessarily ready for all the things that we’re inventing.”

    How confident are you that you have enough data to support the conclusion that an ARIA tabbed interface can not be made to be more effective than the alternative that you proposed?

    After testing, did you iterate on the ARIA implementation in ways that both maintained the key elements of the ARIA design pattern and included features to mitigate or eliminate the issues you found during user testing?

    Did you test with both people who first experienced GUIs with a screen reader outside the web context and with people who have lived primarily on the web for their entire life as a screen reader user? If so, was there any difference in outcomes for these 2 groups?

    I question the conclusion regarding pass-through. I am not aware of any screen reader that will not operate ARIA tabs in either reading mode or interactive mode. I am also not aware of any screen reader that uses “Alt” as its pass through key.

  11. Priti Rohra says:

    I have a question here: when you’ll removed the aria attributes from the tab example, why was role=presentation left as is?
    Due to the presence of role presentation in the element, Jaws did not announced the number of list items for me. As an end-user, I want to know how many links/options are available…

    A suggestion: it would be great to remove the role presentation from the list mark-up. Do you agree?

    1. Jeff Smith says:

      Hi Priti, I totally agree, thanks for pointing that out. That was an oversight on my part in the code snippet embedded in the article. It had been removed from the full Codepen example, but for some reason that change hadn’t made it’s way over here.

  12. Michiel Bijl says:

    If you feel there is an issue with the Tabs design pattern, can you file issues against it on GitHub?

    https://github.com/w3c/aria-practices/issues

    Relevant issues:
    https://github.com/w3c/aria-practices/issues/21
    https://github.com/w3c/aria-practices/issues/14

Hi there! We've closed the comments after a week of spirited discussion on this post. If there's something we've missed, please reach out and let us know.