New Dec 7, 2024

Don’t Use aria-label on Static Text Elements

More Front-end Bloggers All from Ben Myers View Don’t Use aria-label on Static Text Elements on benmyers.dev

Too Long; Didn’t Read

Don’t use the aria-label or aria-labelledby attributes on <div>s, <span>s, or other elements representing static/noninteractive text-level semantics, such as <p>, <strong>, <em>, and so forth, unless those elements’ roles have been overridden with roles that expect accessible names.

That’s a bit of a mouthful, and I couldn’t fit it all in the title.

The Antipattern

A very common accessibility bug involves applying the aria-label or aria-labelledby attributes to static, text-level semantics, especially <div>s and <span>s.

<!-- 🚨 The following examples are all invalid 🚨 -->

<span aria-label="Vegetarian">
	🌱
</span>

<div aria-labelledby="about">
	<h2 id="about">
		About
	</h2>
</div>

<div tabindex="-1" aria-label="Draggable item. Click, tap, or press Space to select. Drag, or use arrow keys to move.">
	<!-- … -->
</div>

However, aria-label and aria-labelledby aren’t permitted on these elements — at least, not without also changing those elements’ roles. This means that in most browser/screenreader combinations (we’ll get to a notable exception shortly), users generally won’t receive invalidly applied aria-labels or aria-labelledbys, making these accessibility “fixes” anything but.

The short, rule-of-thumb-friendly explanation here is that aria-label and aria-labelledby are generally intended for interactive elements (buttons, links, form controls) and landmark regions.

The longer, more precise explanation is that HTML elements are mapped to roles, which specify which kind of thing the element represents. Certain ARIA attributes are only permitted on certain roles. aria-label and aria-labelledby replace an element’s accessible name, which only some roles are permitted to have in the first place. The way aria-label and aria-labelledby are defined in the ARIA 1.2 spec, they are permitted on any role except the following: caption, code, deletion, emphasis, generic, insertion, paragraph, presentation, strong, subscript, and superscript — generally, your static, noninteractive, text-level semantics. At time of writing, the ARIA 1.3 draft spec, which browsers have taken a headstart in supporting, also prohibits aria-label and aria-labelledby on the definition, mark, none, suggestion, term, and time roles. This means that, per the specs, the following elements aren’t allowed an aria-label or aria-labelledby out of the box, until you start overriding roles:

Here there be chonky tables

The following tables were assembled by crossreferencing the ARIA 1.2 spec and ARIA 1.3 draft spec with the HTML Accessibility API Mappings 1.0 draft spec. These tables almost certainly aren’t perfect, but should hopefully be complete enough for most scenarios.

Roles Prohibited from aria-label or aria-labelledby in ARIA 1.2
Role HTML Elements with Default Role
caption
  • <caption>
  • <figcaption>
code
  • <code>
deletion
  • <del>
  • <s>
emphasis
  • <em>
generic
  • Custom elements
  • <a> without an href
  • <area> without an href
  • <b>
  • <bdi>
  • <bdo>
  • <body>
  • <data>
  • <div>
  • <footer> (when scoped to <main> or other sectioning content)
  • <header> (when scoped to <main> or other sectioning content)
  • <i>
  • <pre>
  • <q>
  • <samp>
  • <small>
  • <span>
  • <u>
insertion
  • <ins>
paragraph
  • <p>
presentation None.
strong
  • <strong>
subscript
  • <sub>
superscript
  • <sup>
Roles Newly Prohibited from aria-label or aria-labelledby in ARIA 1.3 Draft
Role HTML Elements with Default Role
definition
  • <dd>
mark
  • <mark>
none None.
suggestion None.
term
  • <dt>
time
  • <time>

This matters because browsers adhere to these specs when assembling accessibility trees for screenreaders to consume, and screenreaders are generally built around supporting these specs. It’s less that aria-label doesn’t “work” on static, text-level semantics, but that it’s not even intended to.note 1

If a browser/screenreader combination does handle aria-label and aria-labelledby on static elements like it does permitted roles, that’s an exception to the rule. Which brings us to a common source of confusion:

But VoiceOver…

It’s important to test changes with actual assistive technologies like screenreaders, but this can cause a footgun of its own if we test just one tool and assume that its behavior is representative of all similar tools.

We can see a solid example of this with the VoiceOver screenreader built into macOS. When it comes to aria-labels on generic elements, VoiceOver generally does announce the contents of the aria-label. If that’s the behavior you were expecting, then testing with VoiceOver alone would seem to suggest that this is a condoned, functioning pattern. In actuality, VoiceOver is doing what many user agents do in the face of invalid code: compensating for developers’ misguided intent so as to not penalize users. That aria-label “works” on generic elements in VoiceOver is a nonstandard remediation of noncompliant code, not an endorsement of a technique working as intended.

As WebAIM’s surveys of screenreader users have borne out, VoiceOver for macOS is severely overrepresented by developers and site/app testers compared to disabled day-to-day screenreader users.note 2 When relying on solely VoiceOver for macOS when testing, developers and testers are optimizing for a platform that few disabled users are actually on, with no sense of the expense caused to users on other platforms.

This isn’t to say you shouldn’t test on VoiceOver or consider the VoiceOver user experience… just that it should be one tool of many in your accessibility testing toolkit.

Alternatives

If we can’t put aria-label or aria-labelledby on static text elements, what should we do instead? It depends, but here’s how I’d approach a few different scenarios:

Was the Label Addressing a Problem Worth Solving in the First Place?

aria-label is a code smell — not necessarily inherently wrong, but often a sign that we might be going off the beaten path. In some cases, the aria-label might have been put in place to address a perceived problem that might not have been worth solving in the first place, or for which a solution could make things worse in other ways.

For instance, sometimes developers will attempt to use aria-label to micromanage screenreaders’ pronunciations of words. In attempting to fix pronunciations, the resulting markup hacks can often make the text completely inscrutable in braille output,note 3 and can complicate voice control usage as well. Meanwhile, pronunciation depends heavily on which text-to-speech engine is in use, and we’re assuming the mispronunciation is even a real, blocking problem in the first place.

On a similar token, sometimes aria-label is used to provide verbose, redundant, potentially off-base control hints, which we could opt to rip out.

These kinds of techniques often arise from incomplete understandings of how screenreader users navigate the web as well as unvalidated assumptions about how they would prefer to receive information, and so the best alternative just might be removing those aria-labels and aria-labelledbys.

Use Visible Text

In some cases, the aria-label was intended to serve as a sort of alternative text.

In the case of iconography, oftentimes we can opt to rework the design in favor of exposing the information as raw, visible, universal text. After all, if blind readers would benefit from some extra context or clarity, who’s to say sighted readers wouldn’t benefit from the same?

<!-- Instead of… -->
<span aria-label="Vegetarian">
	🌱
</span>

<!-- Try… -->
<span>🌱 Vegetarian</span>

<!-- Or maybe… -->
<span>
	<span aria-hidden="true">🌱</span>
	Vegetarian
</span>

Use Visually-Hidden Text

Ah, the design remains firm, unbudging. We can’t clutter the experience with visible text, it would seem.

Another thing we could do then is a one–two punch of marking the visible contents as aria-hidden, and then using visually-hidden styles to provide an alternative for screenreaders to expose:

<!-- Instead of… -->
<span aria-label="Vegetarian">
	🌱
</span>

<!-- You could do… -->
<span aria-hidden="true">🌱</span>
<span class="visually-hidden">Vegetarian</span>

Use More Semantically Applicable Elements

<div> doesn’t accept an aria-labelledby, but if we’re trying to apply one pointing it to a heading, then chances are good that we’re trying to mark out a region of the page, and what we really want is something more like a labeled <section> or <article> element instead.

<!-- Instead of… -->
<div aria-labelledby="about">
	<h2 id="about">
		About
	</h2>
	<p></p>
</div>

<!-- Let’s make a useful landmark -->
<section aria-labelledby="about">
	<h2 id="about">
		About
	</h2>
	<p></p>
</section>

This is especially true for interactive elements — reverse-engineering all of the accessibility requirements for interactive elements often just isn’t worth it.

Add an Applicable Role

In some cases, we actually might want to keep the aria-label or aria-labelledby, and just add an applicable role.

<!-- Instead of… -->
<span aria-label="Vegetarian">
	🌱
</span>
<span aria-label="Kaomoji table flip">
	(╯°□°)╯︵ ┻━┻
</span>

<!-- It might be more appropriate to expose these like images… -->
<span role="img" aria-label="Vegetarian">
	🌱
</span>
<span role="img" aria-label="Kaomoji table flip">
	(╯°□°)╯︵ ┻━┻
</span>

Footnotes

  1. I often see discussions around aria-label on static elements get framed as whether it “works” in a given browser/screenreader combination or not. That said, whether something “works” is often more of a value judgment based how a developer expects things to behave based on their understanding of the world, with little consideration given that the developer could be misguided and their expectations misplaced. If something behaves like a developer expects, but that behavior goes against what’s been spec’d out… is it really fair to call that “working”? |

  2. In the 2023–2024 screenreader user survey, just 8.2% of disabled respondents reported using VoiceOver for macOS as their primary screenreader, whereas 23.7% of nondisabled respondents (generally understood to be developers, testers, and other accessibility professionals) reported using VoiceOver for macOS as their primary screenreader. This jives with the note further down that nondisabled users were nearly three times likelier to use macOS than disabled users were. |

  3. In the same 2023–2024 screenreader user survey, 38% of disabled respondents reported that they use their screenreader with braille output. Assuming this survey is representative (which, as with any survey, is its own can of worms), this means that pronunciation-tackling markup hacks have the potential to confuse about 2 out of every 5 screenreader users, rather than (potentially) clarifying things for those users. |


Originally posted on my blog, , as Don’t Use aria-label on Static Text Elements

Scroll to top