ARIA Rule

aria-label must not be used on div, span or p without a role aria-prohibited-attr

aria-label and aria-labelledby only work on elements that can have a name: controls, landmarks, images, headings, tables and similar. On a plain div, span or p (and on a handful of roles like paragraph, code and presentation) they are prohibited. Browsers mostly ignore them there, so a label that looks helpful in the source is never spoken.

Websight reports this as Elements must only use permitted ARIA attributes

Who it affects

Someone using a screen reader arrows across a star rating and hears the raw symbols, star star star star, or nothing. The 4 out of 5 the developer wrote is never spoken.

Someone using a screen reader on a browser that does honour it hears the label but with the element's real content hidden, which can swallow a whole paragraph of text.

Someone using voice control tries to say the label to reach the element and nothing responds, because it is not a control and has no usable name.

Broken versus fixed

Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.

Broken

Looks right. A screen reader reads the characters: black star, black star, black star, black star, white star, 128 reviews. The aria-label on a plain span is ignored.

Fixed

Announced: 4 out of 5 stars, image, 128 reviews. role="img" makes the span a single nameable thing, and the label replaces the symbols.

Show the markup behind both examples
Broken
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:10px}.stars{color:#d69e2e;font-size:22px;letter-spacing:2px}.n{color:#4a5568;font-size:14px}</style>
<div class="row">
  <span class="stars" aria-label="4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
  <span class="n">128 reviews</span>
</div>
Fixed
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:10px}.stars{color:#d69e2e;font-size:22px;letter-spacing:2px}.n{color:#4a5568;font-size:14px}</style>
<div class="row">
  <span class="stars" role="img" aria-label="4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
  <span class="n">128 reviews</span>
</div>

Test it by hand in two minutes

  1. Search the page source for aria-label= and aria-labelledby=. For each hit, look at the element it is on.
  2. If the element is a div, span, p or similar with no role attribute, the label is prohibited and probably ignored.
  3. In Chrome DevTools, select the element and open the Accessibility pane. If the computed Name is empty or shows the raw text rather than your label, the browser has discarded it.
  4. Turn on VoiceOver (Cmd+F5) or NVDA and read through the area. You should hear the words you wrote, once, and not the raw symbols or a duplicate.

The fix

Before
<span aria-label="4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>
After
<span role="img" aria-label="4 out of 5 stars">&#9733;&#9733;&#9733;&#9733;&#9734;</span>

Give the element a role that can carry a name, or move the label to the control, heading or image it was meant for. For a rating made of symbols, role="img" with the rating as the label is the usual answer.

Label on a wrapper div around a field

Before
<div aria-label="Postcode">
  <input type="text" name="postcode">
</div>
After
<div>
  <label for="postcode">Postcode</label>
  <input id="postcode" type="text" name="postcode">
</div>

The input is the thing that needs a name. A visible label element is better than aria-label because sighted people see it too.

Label on a paragraph

Before
<p aria-label="Summary">Your order will arrive on Thursday.</p>
After
<p>Your order will arrive on Thursday.</p>

A paragraph cannot be named and does not need one. If you want a heading, use a heading element above it.

Common mistakes

  • Adding role="text" or role="generic" to make the scanner stop; neither allows a label.
  • Adding role="presentation" to the element, which removes it from the accessibility tree along with its label.
  • Moving the label to a title attribute, which is read inconsistently and not at all on touch.
  • Wrapping the content in a button or link just so it can be named, when it is not interactive.
  • Using role="img" on a span that contains real sentences, which hides every word except the label.

WCAG criteria this rule maps to

axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:

The scanner can see a naming attribute on an element whose role (or lack of one) prohibits it. It cannot tell what the label was supposed to describe, so decide the right role or target yourself. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.