What happens with aria-labelledby, aria-label and aria-describedby
on static HTML elements?
An interesting Twitter thread sprung up from a Tweet about overriding elements with aria-label with a follow up thread with my colleagues.
I was asked to test the results of aria-label on static content. This is what is below, along with aria-labelledby and aria-describedby, as well as an examination of what is "supposed to happen" according to the Accessible Name computation.
Conclusion: TLDR
Screen readers are all over the map on what they do when an aria-label, aria-labelledby, and aria-describedby on static content
Results
-
aria-label,aria-labelledbyandaria-describedbyare robustly supported for interactive content elements such as links and form controls including the manyinputtypes. - OK on the
<nav>, and<main>elements but not on<footer>,<section>,<article>,<aside>or<header>. - OK on
divelements withrole=navigation,role=search,role=main,role=img. - OK on
tableelement.
Quirks and Quarks when aria-label, aria-labelledby and aria-describedby are static content
| JAWS | NVDA | VoiceOver | Talkback | |
|---|---|---|---|---|
aria-labelledby and aria-label |
Ignored on aria-describedby well supported on static content |
Aria-label, aria-labelledby are override headings. On other elements there is no aria-label aria-labelledby read. |
All the headings are overridden. User then has to interact with heading to hear it, but would not discover that easily. Other elements read aria-label when virtual cursor hits the elements and then let user enter and read the contents. |
All the static content is overridden except list items which are ignored (weird) |
| aria-describedby | Well supported on static content |
Not supported on static content |
Not supported on static content | Well supported on static content |
aria-label or aria-labelledby.role=banner, role=complementary, role=contentinfo. NVDA, VoiceOver, and Talkback are OK
aria-label, aria-labelledby and aria-describedby work well on table, th and td elements with a few exceptions for NVDA, VoiceOver on iOS, and Talkback discussed in next section. aria-label or aria-labelledby on any heading elements because it overrides them on NVDA, VoiceOver and Talkback. JAWS ignores them. aria-label or aria-labelledby on any other non-interactive content such as p, legend, li, or ul, because it is ignored. aria-label or aria-labelledby on a span or div unless its given a role. When aria-label or aria-labelledby are on interactive roles (such as a link or button) or an img role, they override the contents of the div or span. Other roles besides Landmarks (discussed above) are ignored.aria-describedby on a span or div will be ignored by NVDA and VoiceOver unless given an interactive role, an image or landmark role. JAWS and Talkback are OK. aria-describedby will be ignored by NVDA and VoiceOver on any other static content. JAWS and Talkback are OK.All of the above also work the same in iframes. Both aria-label and aria-labelledby have the same behaviour with screen readers and the Accessibility API, but aria-label should be reserved for when there is no visible text on the page to reference or when keeping track of id values would be too difficult.
I filed an issue with the ARIA spec to define the term "user interface elements" (do they include static elements?) with the hope that it will help screen readers manufacturers know what to do.
Short summary of findings
- JAWS on WIN10 ignores
aria-labeloraria-labelledbyon all static content except fornav,main,table,th, andtd, which it reads correctly (all browsers). It gives user option to heararia-describedbyon all static content. - NVDA on WIN10 overrides heading text with
aria-labeloraria-labelledby, ignores it on other static content except fornavwhich it reads correctly (all browsers). It ignoresaria-describedbyon all static content unless it's been given an interactive role and tabindex=0, and then only if the users tabs to it (not arrows to it). It reads correctlyaria-label,aria-labelledby,aria-describedbyon thetableelement but notthortd - VoiceOver on MacOS overrides heading text with
aria-labeloraria-labelledby, user can interact with heading to dig in and get the text, but most users would miss that because its not announced when read. Other elements readaria-label,aria-labelledbyandaria-describedbywhen virtual cursor hits the elements and then let user enter and read the contents. (Chrome and Safari) - VoiceOver on iOS. All the headings are overridden by the VO, ignores it on other static content except for
navwhich it reads correctly (Safari), It only readaria-describedbyif its on an interactive element, an image role, or a landmark role. Poor support ofaria-label,aria-labelledbyandaria-describedbyontable,thortd - Talkback on Android. All static text is overridden by
aria-labeloraria-labelledbyexcept forulandliwhich are ignored,navandtableworks correctly. It always readsaria-describedbyon all static content.
What happens when roles are added?
- If the role is an interactive
role(that can be clicked on such as button or link) or an image role thearia-labeloraria-labelledbyoverrides the text - If its a heading
role,aria-labeloraria-labelledbyoverrides it on NVDA, VoiceOver and Talkback. JAWS ignores thearia-labeloraria-labelledby. - If the
roleis a static role thenaria-labelwill be ignored by all screen readers except Talkback which overrides the static content (except if itslistitemrole, then its ignored).
Static text Element tests with aria-roles with aria-label, aria-labelledby and aria describedby
BEGIN TEST ==========This is an h1 with aria-label="test 1"
h2 with aria-label="test 2"
h3 with aria-label="test 3"
h4 with aria-label="test 4"
h5 with aria-label="test 5"
h6 with aria-label="test 6"
p element with aria-label="test 8"
span element with aria-label="test 9"- li with aria-label="Test 11". It is inside of a ul element
- li element inside ul element. The ul has aria-label="Test 11"
| This is a table with aria-label="test21" on table element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-label="test22" on th element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-label="test23" on td element | header 2 |
|---|---|
| td 1 | td 2 |
aria-labelledby="static-text" on an h1 referencing text below
h2 with aria-labelledby="static-text"
h3 with aria-labelledby="static-text"
h4 with aria-labelledby="static-text"
h5 with aria-labelledby="static-text"
h6 with aria-labelledby="static-text"
p element with aria-labelledby="static-text"
span element with aria-labelledby="static-text"- li with aria-labelledby="static-text" . It is inside of a ul element
- li element inside ul element. The ul has aria-labelledby="static-text"
| This is a table with aria-labelledby="static-text" on table element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-labelledby="static-text" on th element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-labelledby="static-text" on td element | header 2 |
|---|---|
| td 1 | td 2 |
aria-describedby="static-text" on an h1 referencing text below
h2 with aria-describedby="static-text"
h3 with aria-describedby="static-text"
h4 with aria-describedby="static-text"
h5 with aria-describedby="static-text"
h6 with aria-describedby="static-text"
p element with aria-describedby="static-text"
span element with aria-describedby="static-text"- li with aria-describedby="static-text" . It is inside of a ul element
- li element inside ul element. The ul has aria-describedby="static-text"
| This is a table with aria-describedby="static-text" on table element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-describedby="static-text" on th element | header 2 |
|---|---|
| td 1 | td 2 |
| This is a table with aria-describedby="static-text" on td element | header 2 |
|---|---|
| td 1 | td 2 |
End TEST ==========
Static text Elements with role attributes and aria-label, aria-labelledby and aria describedby
BEGIN TEST ======= aria-label ===
span element with aria-label="test 12" with role=img
div element with aria-label="test 15" with role=button and tabindex=0
span element with aria-label="test 19" with role=listitem
=== aria-labelledby ===
span element with aria-labelledby="static-text" with role=img
div element with aria-labelledby="static-text" with role=button and tabindex=0
span element with aria-labelledby="static-text" with role=listitem
=== aria-describedby ===
span element with aria-describedby="static-text" with role=img
div element with aria-describedby="static-text" with role=button and tabindex=0
span element with aria-describedby="static-text" with role=listitem
END OF TEST ===============
Results
| JAWS | NVDA | VoiceOver | Talkback | |
|---|---|---|---|---|
| FireFox (Sept 2018) | Aria-label, aria-labelledby are ignored on all static content unless it has a an interactive role, aria-describedby well supported on static content |
Aria-label, aria-labelledby are override headings. On other elements there is no aria-label aria-labelledby read. aria-describedby pooly supported on static content |
N/A | N/A |
| IE (Sept 2018) | Aria-label, aria-labelledby are ignored on all static content unless it has a an interactive role, aria-describedby well supported on static content |
Aria-label, aria-labelledby are override headings. On other elements there is no aria-label aria-labelledby read. aria-describedby pooly supported on static content |
N/A | N/A |
| Chrome (Sept 2018) | Aria-label, aria-labelledby are ignored on all static content unless it has a an interactive role, aria-describedby well supported on static content |
Aria-label, aria-labelledby are override headings. On other elements there is no aria-label aria-labelledby read. aria-describedby pooly supported on static content |
All the headings are overridden by the VO, User then has to interact with heading to hear it, but would not discover that easily. Other elements read aria-describedby pooly supported on static content |
All the static content is overridden except list items which are ignored (weird) aria-describedby well supported on static content |
Safari MacOS (Sept 2018) |
N/A | N/A | All the headings are overridden by the VO, User then has to interact with heading to hear it, but would not discover that easily. Other elements read aria-describedby pooly supported on static content |
N/A |
Safari iOS (Sept 2018) |
N/A | N/A | All the headings are overridden by the VO. aria-describedby pooly supported on static content |
N/A |
What do the Specs
say?
The Accessible Name Computation spec provides a calculation of an accessible NAME. the definition says:
The accessible name is the name of a user interface element. ...So I tried to look up "user interface element", in the glossary. There is no definition for "user interface element" in the ARIA spec, the Accessible Name Computation spec or the HTML 5.2. It is clear that different assistive technologies are interpreting this differently. JAWS doesn't override headings with
aria-label, which NVDA, VO on iOS and MacOS do. So these AT's are interpretting a heading as a user interface element. I filed a bug with the aria spec and will update this article with the results of that discussion.
Feel free to comment on Twitter @davidmacd
Author information:
David MacDonald is a veteran WCAG member, co-editor of Using WAI ARIA in HTML5 and HTML5 Accessibility Task Force Member. Opinions are my own.
CONTACT US
For a quote or just to chat about your organization's needs
PHONE