Even with the best of intentions and diligent searching it is still rather difficult to work out how to correctly use WAI-ARIA even for rather simple use cases.
Author: Detlev Fischer (@wcagtest)
Imagine you are a developer trying to work out how to implement a simple dynamic element, actually something very simple you have some sort of heading and when you activate it, it should expand to reveal a previously hidden section underneath.
You know that WAI-ARIA can be used to improve the accessibility of dynamic content for screen reader users. You have worked out how to use
aria-hidden to hide visually hidden content also for screen reader users you actually just set
aria-hidden and use a CSS rule to control the visibility of the expandable section, and the
aria-pressed state (and in turn, visual appearance) of the button (see a crude example).
You also realize that you should use
role="button" on the link that displays the expandable section since the link doesnt lead anywhere - it just changes the visible state of the section underneath. So the keyboard focus will remain on the link with
role="button", and repeated activation will just toggle the visibility of the expandable section. Fine so far.
Reading further into WAI-ARIA, you realize that there is the
aria-expanded state that could (or should) also be applied you just wonder whether it would be an attribute set on your triggering link with
role="button", or an attribute set on the expandable section.
Delving into WAI-ARIA documentation, you decide to search for aria-expanded and see what comes up (thats how I often approach such questions, but there may be sounder ways). Doing just that, you will get (at my time and place, and searching with Google) in top position a link to an article on aria-expanded by Marco Zehe, then some Microsoft documentation, and in third place, some pretty authoritative looking documentation: ARIA States and Properties - W3C. In the section on
aria-expanded, you find the following definition:
Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed.
Which does not answer your question whether you should set the state on the button or on the expandable section, or on both the or seems to indicate it could be either/or (but not both).
You also find the recommendation:
If the element with the
aria-expandedattribute controls the expansion of another grouping container that is not 'owned by' the element, the author SHOULD reference the container by using the
In other words, the trigger button should in any case carry the
aria-expanded attribute and in addition, the
aria-controls attribute pointing to the
id of the expandable section.
You return to your search engine to find some implementation examples or more concrete advice. Next there is a Paul J. Adams blog entry on
aria-expanded. Paul describes implementation problems of various ways of indicating the expanded state (including, besides
title attributes and hidden text) and reporting some not so encouraging screen reader testing results.
You skip this for now to look for some more authoritative information. Wasnt there an ARIA Best Practices document that should do the trick? You do a search on aria-expanded best practice which brings up in fourth position a fairly authoritative-looking document: Using WAI-ARIA in HTML - W3C. Looking here, you find that
aria-expanded can be used on many (most) aria-roles, including
button - even including the roles
aria-expanded on the page you find a section on the
summary element being used in a scripted polyfill with a recommendation to use
aria-expanded="true", but this is not your use case, so you look further.
Next, you look at a page from the OpenAjax Initiative on using
aria-expanded which is oddly named Example 22 - Hide/Show: Region is exclusive. This page has the benefit of a working implementation looking like a crude tab panel (also supporting keyboard interaction) and code examples.
Here you find the
aria-expanded attribute set on the controlling
role="button", not on the section that is hidden and revealed. It is interesting to note that while the example looks very much like a tab panel, the
tabpanel roles are nowhere to be seen. Maybe look somewhere else?
Going back to Marco Zehes now slightly dated blog entryfrom 2010 that still comes up top in Google when searching just for
aria-expanded, you follow through to the example he pointed to. In this implementation,
aria-expanded is used both on the triggering heading (made keyboard-navigable via
role="button") and on the
ul that wraps round the expandable section. In addition,
aria-controls is set on the trigger and points to the controlled section (the
Finally, you recall another authoritative source, the WAI ARIA 1.0 Authoring Practices. The document seems to have been updated recently, it says "W3C Working Draft 7 March 2013".
aria-expanded here leads straight into a longish explanation of how to implement keyboard navigation in an accordion widget fair enough, since the use case you have in mind can be considered the simplest form of accordion (with just one expandable section). The text describes the proper keyboard handling when tabbing and arrowing through an accordion and has the following snippet:
When the corresponding panel is expanded (its
aria-expandedstate is 'true'), then focus moves to the first focusable element in the panel.
From this, it seems clear that the expandable section (the accordion panel) itself should carry the
aria-expanded attribute. Further down, we are advised that "An accordion should manage the expanded/collapsed state of each tab by maintain[ing] its
aria-expanded state." Which again sounds as if this state should be applied to the tab, i.e., to the accordion header as well. If this is what should be done (apply
aria-expanded both to the trigger (tab, button) and to the section (here: tabpanel) that is expandable, why is this nowhere clearly stated?
Since you want to double-check, you follow the example provided, the Open Ajax Alliance Accordion, which, besides being spelled accordian, does not set the
aria-expanded state on the expandable sections (they have
role="tabpanel" here). So we are back to square one. Maybe there are other examples to confirm this is what we need to do?
aria-expanded attribute is applied only to the expandable
role="tabpanel", not to the triggering headings (
role="tab") these just reference the expandable
divs via the
If I were a developer wanting to use WAI-ARIA on a simple expandable bit of content, I would be rather exasperated by now. Given the inconsistent and confusing state of ARIA documentation and best practice examples available, is it surprising that we see little use of ARIA and many cases where it is used incorrectly?
Last line: Having done all this searching, I am still not sure what would be the proper way of implementing my use case. I would lean to using
aria-expanded only on the element that actually expands and contracts, not on the trigger (as in the jQuery example) but currently, I have little to back up that preference.