18.04.2013
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 display:none
and 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.
aria-expanded
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:
aria-expanded
(state)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-expanded
attribute controls the expansion of another grouping container that is not 'owned by' the element, the author SHOULD reference the container by using thearia-controls
attribute.
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 aria-expanded
, the alt
and 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 alert
and dialog
.
Searching for aria-expanded
on the page you find a section on the summary
element being used in a scripted polyfill with a recommendation to use role="button"
with 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-controls
and 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 li
with 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 tablist
, tab
and 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 tabindex
and 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 ul
).
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".
Searching for 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-expanded
state 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?
Further searching for "accordion widget" brings up a jQuery example, the jQuery Accordion. jQuery is a popular JavaScript framework and the team has made an effort to use WAI-ARIA, so this should be interesting to look at. Looking at the source code, you find that here, the aria-expanded
attribute is applied only to the expandable div
s with role="tabpanel"
, not to the triggering headings (h3
with role="tab"
) these just reference the expandable div
s via the aria-controls
property.
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.
© 2022 DIAS GmbH | Imprint | Accessibility | Privacy Policy