Easy ARIA Tip #5: aria-expanded and aria-controls

In this Easy ARIA tip, I will give you a bit of a hint on how to make not too complex, but still dynamic, menus accessible. We often encounter menus that pop in and out upon a mouse click or activation of an element using the keyboard.

An example can be found at this German blog site. Look for the “Archive” heading, which is a clickable element that shows or hides the archive choices offered by this blog.

Right now,NVDA speaks this item as “clickable”, so the blind user already gets notified that there is a possibility here to press Enter on the item and something will happen. Now how cool would it be if, in addition, NVDA would tell me that something will be expanded, or is currently expanded, and I can press Enter to collapse it?

Fortunately, we have WAI-ARIA to rescue us from this desire! :)

The global attribute aria-expanded is used for exactly this purpose. It takes one of two values: true or false. true means a section that this element denotes is currently expanded (visible), false means the expandable section or items is/are currently collapsed (invisible). In the above example, aria-expanded must be defined, and by default set to false. In the Javascript that handles the expansion and collapsing of the categories, another code block must be added to touch this attribute and change its value to true when the categories are made visible, and back to false when they are made invisible. Since there is already JavaScript in place to handle the visibility of the categories, this can be plugged in very easily.

There is one more piece to this: Modern screen readers such as NVDA, Orca or modern versions of the commercial screen readers, can also make use of another attribute that tells which element is actually being affected. In this case, the list of categories. This is done through an attribute called aria-controls. The value of this attribute is the ID of the affected element and is set either once or whenever the controlled element changes. In this example, the value would point to the html:ul element with the ID of “archivliste”. The attribute gets set on the same element that also gets aria-expanded and does all the magic. Screen readers then know which element is being referenced, by something called Accessible Relations.

In summary:

  • aria-expanded receives a value of “true” when the elements in question are visible. It is set to “false” when those elements are actually not visible.
  • aria-controls is set to the ID of the top level element that gets made visible or invisible.

Both attributes get set on the element that actually does the magic (the same element that has the onclick handler or click/keyboard event listener).

[Update] One word about placement of the expandable items: Ideally, they should be following the item that expands and collapses them, as can be seen in the example above. The list of archive months follows the heading that has the click handler to expand and collapse it. The result is that screen reader users can expand the items and simply down arrow without having to look for the new content. This makes it feel very natural and efficient.

Also, some screen readers have intelligent detection of dynamic changes and speak them automatically. This is sort of what WAI-ARIA live regions do, but without the explicit live region markup. The result is that upon expansion, the new items might automatically be spoken, which might be undesirable. For example, this list of months would be very undesirable to be rattled off by the synthesizer whenever the list gets expanded. To prevent this, another attribute can be applied, aria-live with its value set to “off”. This prevents supporting screen readers from ever treating this particular region as a live region. This attribute, however, in the example above, would go on the html:ul element, not the element that expands and collapses the list.

Thanks to Aaron Leventhal for these two excellent points![/update]

Previous Easy ARIA Tips

  1. aria-required
  2. aria-labelledby and aria-describedby
  3. aria-invalid and role “alert”
  4. Landmarks

21 comments:

  1. Der Artikel kommt passend als Reminder für mein Projekt; aria-expanded wollte ich ja auch schon längst eingebaut haben – Frisch an’s Werk!

  2. Hi Marco, does aria-controls affect the behavior of any of the screen readers? Or can the screen reader user navigate to what it points to?

    When the item is expanded, should the author make it next in the tab order so that users can navigate to it with a tab key when it’s expanded? Perhaps from there the user would navigate with more tab keys or arrow keys depending on what it is.

    Finally, I think some screen readers may automatically try to read live changes on a page when a user’s click or key press caused the change. Firefox has an object attribute to tell the AT when this has happened. I’m not sure if anyone has implemented that. If they have, it might be important to put aria-live=”off” on the expanding region.

  3. Hi Marco, Good article. Aaron has some good questions in the comment section.

    Also a comment about the comments of your blog: they pick up a lot of Twitter repeats which ads a lot of repetative comments making it easy to miss real discussion…

  4. Hi Aaron, sorry for the delay in responding! You wrote:

    does aria-controls affect the behavior of any of the screen readers? Or can the screen reader user navigate to what it points to?

    Theoretically, a screen reader can use the relational info provided by IAccessible2/ATK to provide a navigational means to navigate to that content. However, I am not aware than any screen readr actually uses that info yet. But perhaps this article inspires some creativity among the screen reader developers!

    When the item is expanded, should the author make it next in the tab order so that users can navigate to it with a tab key when it’s expanded?

    Yes, this is an excellent point, and I’ve updated the article to reflect that. Thanks! So far, I have seen mostly cases where the newly expanded content actually follows the item that expands the new chunk, directly in the source code. In this case, screen readers pick it up. The example I linked to, does this. The list of archive months appears in the source code directly below the “Archive” heading, which makes it easily navigable just by down arrowing.

    Finally, I think some screen readers may automatically try to read live changes on a page when a user’s click or key press caused the change. Firefox has an object attribute to tell the AT when this has happened. I’m not sure if anyone has implemented that. If they have, it might be important to put aria-live=”off” on the expanding region.

    I am not aware of any Windows screen reader trying to do automatic detection of non-marked up live regions. Orca on GNOME does that to some extent, but it didn’t do it for me in this example. I guess it depends on testing the web page with a screen reader (this should be done anyway), and set this attribute if necessary. I’ll put a note in the article update to that effect.

  5. Does it make sense to mark a region as “aria-expanded: false”, if it’s removed from the DOM with “display: none”?

    If I have construct with many ARIA-stuff inside, do you think that’s too much? It declares the whole box with the expandable content inside als aria-live:polite, gives the “Close”-Button a role:button and the expandable fulltext has a aria-expanded:true/false, if you click on the headline or close button.

    Here is an example:

    Headline
    Close Box
    Full text only visible if you click on the h2-element

  6. 1/
    IMO an element X which “controls the expansion of another grouping container that is not ‘owned by’ the element” shouldn’t have an aria-expanded attribute because when the element Y it is controlling collapse the element X is still visible (expanded).

    2/
    aria-controls makes no sense if javascript is disabled (unless you are using the HTML5 details tag)

    3/
    if the controlling element doesn’t have an aria-expanded attribute, a tabindex will still make them “clickable”?

  7. @anon
    2: jepp you are right!
    3: Ill guess so! But why should a controlling element not have an expaned attribute?

    Anyway in this posted is “aria-live” mentioned.
    I would be more than happy if you could make an Aria-Quick-Tip #6 with that topic.

    Regards Type!

  8. Finally, I think some screen readers may automatically try to read live changes on a page when a user’s click or key press caused the change. Firefox has an object attribute to tell the AT when this has happened. I’m not sure if anyone has implemented that.

What are your thoughts?