CSS tabs, part II: Accessibility

CSS tabs, part II - Accessibility

Recently I’ve been writing about CSS tabs. Topic was surprisingly popular, gaining several thousand users to my page.

What was even more surprising were comments about accessibility. Although my initial idea was to present just a CSS technique for tabs, I decided to investigate a little bit more and add accessibility to my solution.

Existing solutions

CSS tabs are very old topic apparently, I’ve even found an article dating back in 2003. And it is a very popular topic, too, search results returned dozens of articles. I decided to document every article in this Github repository.

If you have an article that is not in the list, please add it by making a pull request.


Reading all this articles made me realize that accessibility is a major issue nowadays. And accessibility is hard. But that doesn’t mean that we should ignore it. Quite the contrary, we should learn it and apply it.


We need to find a tool to test our tabs for accessibility. Web Accessibility Initiative provides us with the list of tools here. I prefer WAVE, web accessibility evaluation tool, because it is available from Firefox Web Developer Toolbar, under section Tools > “Validate Accessibility”.


Since I was developing locallyWAVE couldn’t access my localhost. I found solution in ngrok, a tool that makes tunnels for localhost. To create a tunnel for your localhost, download ngrok executable file, place it in project root, open Command Prompt and start it using ngrok http 9000 command. Last number is the port number of your application which is 9000 in my case. Then open page, copy tunnel URL and paste it in WAVE application. Here’s how it looks in action (and yes, that’s Pokemon theme for Firefox):


ngrok in action
ngrok in action


WAVE detected a couple of contrast errors. That’s the easy part. We should use stronger colors for text and lighter colors for background. Visually impaired people shouldn’t have problems with reading tabs labels and content now. And there’s no errors from WAVE, too.

aria attributes

Our tabs are not yet accessible. To make it accessible for every user, device and tool, we should add aria attributes. aria attributes are used to add context for elements. That way tools and devices are able to read the content and reproduce it in a way that every user could understand it.

Screen readers

We should test our tabs in some of the assistive technology tools, because results could help us start adding accessibility. I decided to use Jaws and NVDA, both available for free on Windows platform. First thing I noticed, after running these tools, was that HTML structure is not suitable for accessibility. We need to add div wrappers for tab labels and tab content.

aria roles

Now we could add aria attributes. There are specific aria roles for tabs:

  • tablist,
  • tab and
  • tabpanel.


Every role could have required and optional attributes. Required attributes are easy, because we know we should add it to an element. Optional attributes are problem: how can we know which ones work and which ones don’t? Ideally, every attribute should work. But as I discovered, they don’t.

Trial and error

Because there are so many tools and devices and documentation is overwhelming, I decided to use trial and error method this time. After few hours, I came up with final solution. You could see it in this pen:


See the Pen Accessible CSS tabs by CiTA (@CiTA) on CodePen.

Radio buttons

In previous article, radio inputs were hidden. I decided to use them as a part of design for tabs. Most users should be familiar with radio buttons, as they are widely used on the web.

To position every radio input, we could use absolute position with top and left offsets. Tricky part was to make it responsive. nth-of-type selector is used to adjust position for every radio button.


To add some interaction, we should add a little bit of JavaScript. It is mostly used for changing states, like aria-activedescendantaria-selected and aria-expandedHTML and CSS are still used for handling tabs.


Now that radio buttons are visible, user could navigate through tab labels more intuitively using left and right arrow keys.

Also, we should add trigger to help users jump to content from tabs. If a user press “Enter” while on the tab label, matching tab content will be focused.

Final thought

Accessibility is hard to implement, but non accessible content is even harder to interpret for impaired users. We should try our best and make our content accessible.

But on the other hand, if you’re making a solution for targeted audience and there are no special request for accessibility, aria attributes may not be necessary. They are hard to implement and very time consuming.

What do you think? What are your experiences?

Leave a comment below or send me a tweet.

  • You say “I decided to use Jaws and NVDO, both available for free on Windows platform.”, but I believe you mean NVDA. Also, are you sure Jaws is available for free? Because the last time I checked it was not.

    Anyway, I don’t think radio buttons are a good fit for Tab Panel even though I wrote about it here http://cssmojo.com/pure-css-tab-panel/

    In my opinion, the best approach is the one that relies on the best (because simplest) markup: http://cssmojo.com/tab-panel-the-right-way/

    • Star Bist

      @thierrykoblentz:disqus, thank you for your comment.
      NVDO is just a type, I did mean NVDA, it is updated.
      Jaws are available on free trial, that’s what I meant.

      I actually read your article about tab panels earlier this year.
      It is a very good article.
      But I disagree that radio buttons aren’t a good fit – if you can make it work, you could use it.
      That’s why I love web, there are so many ways…

  • Simon Taggart

    Hi There!

    Firstly let me say I admire your effort and desire to spread the word about the importance of Accessibility in digital interfaces.

    Unfortunately though the information presented in this article is at times fairly inaccurate and incorrect. Your interpretation of the ARIA specification is a little “off” unfortunately, some of the ARIA used is not required, incorrectly used, or misplaced. For example aria-describedby should be a list of IDs of HTML elements who’s content describe the element in question, not a text string: https://www.w3.org/TR/wai-aria/states_and_properties#aria-describedby. The current implementation unfortunately doesn’t really communicate correctly the type of component you’ve built to screen readers.

    That’s not to say this article shouldn’t exist, I’d just strongly suggest it’s edited to present a much more correct implementation to spread and educate the right ideas. A excellent example of a simple ARIA based tabset can be found at the following link: http://heydonworks.com/practical_aria_examples/#tab-interface. As you can see, the mark up is incredibly simpler, and you only require a small amount of JavaScript to implement the keyboard interaction and showing and hiding of the tab panels.

    Keep writing articles about Accessibility, it’s important. Just update the content in this to better reflect the correct ARIA usage.


    • Star Bist

      @simontaggart:disqus, thank you for your comment.
      I really do want to make web more accessible.

      aria-describedby is now fixed (removed), both on github and codepen.

      Although I fancy your solution, there is no reason not to make other solutions which works, like this one.
      We just need to keep on trying, until every implementation works on every device (which will be never).