Accessible Description Exposure
If you have little experience with ARIA, screen readers, or testing in general, understanding accessible descriptions can be trickier than understanding accessible names (already confusing for many). I have written explanations so many times for clients and in fora that I opted to put this together so I maybe never have to explain it again.
Background
First it’s important to know how an accessible description is computed. The Accessible Name and Description Computation specification handles this, specifically referencing aria-describedby
, and then deferring to the other features such as title
(in very limited circumstances) and <desc>
(for SVGs). In the future, aria-description
may exist and be supported as well.
Next we need to understand where we can assign this description. The ARIA 1.3 draft helpfully tells us which roles cannot be assigned an accessible name through ARIA, which also applies to accessible descriptions. For example, the generic
role is one of them. The generic
role maps to <div>
and <span>
, meaning you cannot assign an aria-describedby
to either element (nor an aria-label
or aria-labelledby
) unless it has an appropriate role.
Finally, to test how this is all exposed to users you need to fire up screen readers. Then you need to pair those screen readers with browsers, ideally using pairings that match what your audience uses. After that, you will need to navigate the page all the different ways users can. This includes understanding screen reader interaction modes, how desktop screen readers and mobile screen readers have different behaviors, and then considering getting some Braille display expertise involved.
Results
While this post is about how and where the accessible description is exposed by assorted screen readers, it has the added benefit of showing you where and how the accessible name is exposed as well. Lucky you.
My test case only looked at a button and a link. Nothing more complex. They both use the same description text, referenced by aria-describedby
.
For the scope of this recap, the term “accName” means accessible name and “accDesc” means accessible description. I wrap the auto-generated text from the screen reader as sample output (the <samp>
element). Since this post is about accessible descriptions, I also wrap accDesc in <strong>
so it is distinct from the accessible name.
For Windows users, Caps Lock is the laptop JAWS key and NVDA key. On macOS, Ctrl + Option combined are the VoiceOver key. Bear this in mind when reading official documentation that references JAWS, NVDA, or VO keys because you will not find those on your keyboard.
Desktop screen readers, with no Braille display:
- JAWS
- Read-all (Caps Lock + ↓)
- accName button
- link accName
- Tab↹
- accName button, accDesc, instructions
- accName link, accDesc
- Virtual cursor (↓)
- accName button
- link accName
- Button navigation (B)
- accName button, accDesc
- Link navigation (V or U)
- link accName
- Buttons list
- accName button
- Links list
- accName
- Focused by script
- accName button, accDesc, instructions
- accName link, accDesc
- Read-all (Caps Lock + ↓)
- NVDA
- Read-all (Caps Lock + ↓)
- button accName
- link accName
- Tab↹
- accName button accDesc
- accName link accDesc
- Virtual cursor (↓)
- button accName
- link accName
- Button navigation (B)
- accName button accDesc
- Link navigation (V or U)
- accName link accDesc
- Buttons list
- accName
- Links list
- accName
- Focused by script
- accName button accDesc
- accName link accDesc
- Read-all (Caps Lock + ↓)
- Narrator
- Read-all (Caps Lock + ↓)
- button accDesc accName
- accName link
- Tab↹
- accName button, accDesc
- link accName
- Virtual cursor (↓)
- button accDesc accName
- link accName
- Button navigation (B)
- accName button accDesc
- Link navigation (K)
- link accName
- Buttons list
- accName
- Links list
- accName
- Focused by script
- accName button, accDesc
- link accName
- Read-all (Caps Lock + ↓)
- VoiceOver
- Read-all (Ctrl + Option + A)
- accName button
- link accName
- Tab↹
- accName button, accDesc, instructions
- link accName, accDesc, instructions
- Virtual cursor (↓)
- button accName, accDesc, instructions
- link accName, element
- Form control navigation (Ctrl + Option + ⌘ + J)
- accName button, accDesc, instructions
- Link navigation (Ctrl + Option + ⌘ + L)
- accName link, accDesc, instructions
- Buttons list
- accName button
- Links list
- accName
- Focused by script
- accName button, accDesc, instructions
- link accName, accDesc, instructions
- Read-all (Ctrl + Option + A)
- Orca
- Read-all (Caps Lock + ;)
- accName push button
- accName link
- Tab↹
- accName push button accDesc
- accName link accDesc
- Virtual cursor (↓)
- button accName accDesc
- link accName
- Button navigation (B)
- accName push button accDesc
- Link navigation (V or U)
- accName link accDesc
- Buttons list (Alt + Shift + B)
- accName
- Links list (Alt + Shift + V or U)
- accName URI
- Focused by script
- accName push button accDesc
- accName link accDesc
- Read-all (Caps Lock + ;)
- ChromeVox on ChromeOS
- Read-all (Launcher + R)
- accName button, accDesc
- accName link, accDesc
- Tab↹
- accName button, accDesc, instructions
- accName link, accDesc, instructions
- Virtual cursor (Launcher + →)
- accName button, accDesc, instructions
- accName link, accDesc, instructions
- Button navigation (Launcher + B)
- accName button, accDesc, instructions
- Link navigation (Launcher + L)
- accName link, accDesc, instructions
- Buttons list
- accName button, accDesc, menu item details, instructions
- Links list
- accName link, accDesc, menu item details, instructions
- Focused by script
- accName button, accDesc, instructions
- accName link, accDesc, instructions
- Read-all (Launcher + R)
Mobile screen readers, with and without paired keyboard:
- TalkBack
- Read-all
- accName button accDesc
- accName link accDesc
- Swipe right
- accName button, accDesc, instructions
- accName link, accDesc, instructions
- Button navigation (Alt + B)
- accName, button accDesc, instructions
- Link navigation (Alt + L)
- accName, link accDesc, instructions
- Navigate by controls
- accName button accDesc, instructions
- Navigate by links
- accName link accDesc, instructions
- Focused by script
- accName button, accDesc, instructions
- accName link, accDesc, instructions
- Read-all
- VoiceOver
- Read-all
- accName button
- accName link
- Swipe right
- accName button, accDesc
- accName link, accDesc
- Button navigation (Ctrl + Alt + Q, B)
- accName button, accDesc
- Link navigation (Ctrl + Alt + Q, L)
- accName link, accDesc
- Navigate by controls
- accName button, accDesc
- Navigate by links
- accName link, accDesc
- Focused by script
- accName
- accName link
- Read-all
Overall, TalkBack exposes the accessible description the most while JAWS does the least. When VoiceOver on iPadOS and NVDA each expose the accessible description, they do so consistently for links and buttons in the same navigation context.
Keep reading for the test case and videos of screen readers handling it.
Interesting note is that all screen readers announce the link and the button the same when you set focus with script as if you had tabbed to it. Except VoiceOver on iDevices. This may be due to heuristics and may behave differently in your project.
Test
View (and fork) the test page on Codepen, or hit the debug view for proper testing.
See the Pen aria-describedby Demo by Adrian Roselli (@aardrian) on CodePen.
The relevant code:
<button type="button" aria-describedby="Desc">Drink me</button>
<p>
<a href="…" aria-describedby="Desc">Follow me</a>
</p>
<p>
Shared description:
<span id="Desc">This is the description for this thing you are on.</span>
</p>
Screen Reader Output
The following sections are videos from assorted popular screen reader and browser pairings. They do not use hot keys (like pressing B to jump to a button) because I forgot them in my first draft.
JAWS
NVDA
Narrator
VoiceOver on macOS
Orca
ChromeVox
TalkBack
VoiceOver on iPadOS
Verdict
Definitely do not rely on the accessible description to convey critical information (such as instructions). Definitely do test it in more than browser dev tools, screen reader logs, and scripted screen reader tools.
This post took a really long time to put together — testing, recording, captioning, clipping, writing up, documenting, re-testing, tweaking, rambling, and so on. If you use this in your job, maybe convince your employer to contract me for some project work. Or maybe buy me a sandwich.
Related
Steve Faulkner has documented how aria-label
and aria-labelledby
are supported:
- Not so short note on aria-label usage – Big Table Edition, 7 November 2020
- aria-labelledby usage notes, 3 April 2022
Scott O’Hara has written on aria-describedby
as well:
- Describing aria-describedby, 5 September 2018
- Issue 946653: Content added to an aria-describedby element is treated as a live region, issue report on Chrome, 27 March 2019, closed as WONTFIX 16 February 2022 (added after comment from Mark below)
Update: 6 April 2022
Added Orca test results performed by eurodiverse.
Update: 16 April 2022
Added test results for when focus is set to the control via script.
Update: 17 April 2022
Made and added video for Orca tests.
Update: 18 April 2022
Added test results and video for ChromeVox on ChromeOS, with thanks to Scott Vinkle for the materials.
Update: 30 August 2023
Early in this post I make an off-hand reference to aria-description
. That property is not in the scope of this post, but I get asked enough about it that it seemed to warrant a brief update.
Scott O’Hara filed VoicerOver Bug 259156 – AX: aria-description not exposed as expected in July and Diane Ko followed up a few days ago with Bug 260835 – AX: aria-description not exposed directly to VO users.
As I implied above, support is still lacking.
Update: 9 October 2023
Safari 17 has arguably broken aria-describedby
. Associated content is moved behind a four-finger interaction (which then requires another keypress), but only if you hear the message that more content is available.
This appears related to the aria-description
issues above owing to Safari trying to get both attributes to behave similarly.
I filed Bug 262895 – AX: `aria-describedby` content hidden behind new interaction. I also confirmed this happens in Safari Technology Preview 180 (which maps to Safari 17.4), though I hope Apple fixes this well before that release.
Update: 10 January 2024
Darin Senneff has done some fresh testing in Dynamic accessible descriptions reference. His key takeaways:
- Don’t rely on accessible descriptions for dynamic information,
- Screen reader navigation methods are not equal,
- Text inputs have broader description support,
- VoiceOver has big issues with accessible descriptions, and
- Changes to accessible descriptions of focused elements are not reliably announced.
13 Comments
Thanks for this write up Adrian. I recently came to this same verdict a few weeks ago when I considered using
aria-describedby
on some toggle buttons, but my own testing with NVDA and JAWS got the same results you did, and the information was important enough that I decided to add it to the accessible name instead. I didn’t even bother testing with Talkback since I knew it wasn’t going to fly, but I kind of wish I would have since it apparently passes with flying colors (what a pleasant surprise that would have been).
hey Adrian,
Are you familiar with the following issue related to aria-describedby:Windows Chrome (only, currently using v99), an active element () with aria-describedby properly associated. If the text that aria-describedby is associated with changes, when NVDA or JAWS are running, that changed text is announced almost as if a live region existed?
Mark
In response to .Hi Mark! I am indeed aware of that. Scott O’Hara reported it just over three years ago on Chrome 73: Issue 946653: Content added to an aria-describedby element is treated as a live region
It was closed almost two months ago as WontFix, with the note
works as intended.
sorry should add aware of this -> https://a11ysupport.io/tests/tech__aria__aria-describedby#assertion-aria-aria-describedby_attribute-convey_description_change-html-input(type-text)_element <- but wondering specifically about
textarea element…
In response to .I may be misunderstanding what you are asking, but I will try to address it by adding detail to what I said above that I should not have excluded.
- The Chrome team closed the issue because Chrome is behaving per the spec. The Core AAM 1.2 specification section 4.8.1 State and Property Change Events lists
aria-describedby
as one of the properties that should fire a change event if its value is updated.- This should apply to
<textarea>
elements as well.- Per the links above, the macOS AX API does not seem to mandate a change event (it is listed as TBD.
Thanks Adrian, learned something new this week. Hope things are going well?
Mark
In response to .Yay! I was useful to someone! And things are well enough that I could track down that info without any angry calls.
Many thanks for that great report!
Thanks for doing the legwork on this. One additional thing of note is that I believe most SRs will announce the description if the control is focused via Javascript, similar to the way they behave for tabbing. I’ve found this useful when focusing fields that have inline error messages.
In response to .James, this post is meant to reduce the speculation I see many devs (and testers) use to make a decision when a simple test could demonstrate the results. As such I updated the test to include buttons to set focus to both of the sample controls.
Fun fact — they all announce the control as if the user had tabbed to it, except VoiceOver on iDevice. VO does not announce the accessible description for either, and it does not announce the control type for the button. This may be a function of heuristics or it may be a hard rule. No idea without making more tests.
Thanks for the suggestion!
Thank you again for this research.
I really don’t understand why screen-readers would behave differently in this case. I would even like to think that this is a bug – users using tab key getting announcements while users using other navigation mechanisms not getting the announcement…
If this is not a bug but a planned behavior – do you maybe know why? This basically means that depending on aria-describedby is not really an option. Especially if you test with screen-reader users that don’t use the tab key at all.
In response to .The differences in accDesc announcement based on navigation method is not a bug. Using the virtual cursor in browse mode is common to quickly move through content and the accDesc is just noise. Same for using read-all. The links and buttons list serve a similar purpose, to quickly identify interactive controls of that type.
When interaction is likely, such as tabbing through interactive controls, then it makes sense to be more verbose. Bear in mind users can adjust this anyway; I am reporting results from default settings.
As for a screen reader user who never uses Tab
, I would be interested to know that use case. Other than reading a plain document with no navigation or any other interactive bits, I am not sure where that scenario might pop up or be useful for the user.
Leave a Comment or Response