← Back to Insights
ARIA labels and accessible names

ARIA Labels Done Right: The First Rule, Accessible Names, and the Mistakes Behind 2026's Regression

A developer at a laptop working carefully through interface code, with a colleague using a screen reader with over-ear headphones nearby. Convey deliberate craft rather than speed. Natural window light, shallow depth of field, candid and dignified, cool indigo and cyan colour grade, clean uncluttered background. No text, no UI overlays, no legible screen content, no logos.

82.7% of the top one million home pages now use ARIA, according to the WebAIM Million 2026 report. ARIA code increased 27% in a single year and is over six times higher than in 2019. In the same period, 95.9% of home pages had detected WCAG 2 failures - up from 94.8% in 2025, reversing six years of small improvements.

That is the paradox this post is about. More ARIA, more failures. The data does not prove causation - pages with more ARIA are also more complex - but the correlation is hard to ignore, and the mechanism is well understood: ARIA labels and roles are easy to add and easy to get wrong, and wrong ARIA is often worse than no ARIA at all.


The First Rule of ARIA (and Why It Gets Ignored)

The W3C's first rule of ARIA use is explicit: "If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so."

The corollary, widely quoted in the accessibility community, is blunt: no ARIA is better than bad ARIA.

The rule gets ignored for two reasons. First, developers reach for ARIA because it looks like a fix - add an attribute, the problem appears solved. Second, automated and AI-assisted coding ("vibe coding") generates ARIA attributes freely, without the contextual judgment the spec requires. The WebAIM Million 2026 report attributes part of the regression to exactly this: third-party frameworks and automated code generation shipping ARIA that is syntactically present but semantically broken.

Home pages with ARIA present averaged 59.1 detected errors versus 42 on pages without ARIA - roughly 17 additional potential barriers. WebAIM is explicit that this is correlation, not proof that ARIA caused the errors. Pages with ARIA are also more complex. But the direction is consistent: the more ARIA attributes present on a page, the more detected errors could be expected.

The practical implication: before you add any ARIA attribute, ask whether a native HTML element already provides the semantics. Usually it does.


What an Accessible Name Actually Is

Every interactive element - button, link, form control, landmark - needs a human-readable name so assistive technologies can announce it. That name is called the accessible name, and it is computed by the browser following the Accessible Name and Description Computation (AccName) algorithm.

The algorithm walks a strict priority order. When a higher-priority source provides a non-empty string, lower-priority sources are ignored:

Accessible Name Computation: Priority Order
PrioritySourceNotes
1 (highest)aria-labelledbyReferences one or more elements by id; their text is concatenated. Wins when present and pointing to valid targets.
2aria-labelA direct string. Used when no aria-labelledby is present. Overrides visible text content.
3Native HTML mechanism<label for> on inputs, alt on images, value on submit buttons, visible text content of <button> and <a>.
4 (lowest)title attributeFallback only. Inconsistently exposed by screen readers; do not rely on it as a primary name source.

The precedence order is where most mistakes happen. Developers add aria-label to an element that already has visible text, not realising that aria-label wins over the text content. The screen reader announces the aria-label value; a voice-control user says the visible text; nothing happens. That is a WCAG 2.5.3 Label in Name failure.


The First Rule in Code: Before and After

<div role="button"> vs <button>

<!-- ❌ Wrong: requires manual keyboard handling, focus management,
     and ARIA state - all of which are built into <button> for free -->
<div role="button" tabindex="0" onclick="doThing()" aria-pressed="false">
  Save
</div>

<!-- ✅ Right: keyboard, focus, and implicit role are native -->
<button type="button" aria-pressed="false">Save</button>

A <div role="button"> is a promise. The W3C is clear: declaring a role means the developer must also provide the expected keyboard behaviour, because ARIA roles do not automatically supply it. A real <button> gives you Enter, Space, focus, and the button role for free.

aria-label on a <span> vs a real <label>

<!-- ❌ Wrong: aria-label on a generic element is prohibited by spec
     and silently ignored by most screen readers -->
<span aria-label="Email address">Email address</span>
<input type="email" id="email" />

<!-- ✅ Right: native association, no ARIA needed -->
<label for="email">Email address</label>
<input type="email" id="email" />

The WAI-ARIA 1.2 spec lists generic - the implicit role of <div> and <span> - as a role where aria-label and aria-labelledby are prohibited. Most screen readers ignore the attribute on these elements entirely, though VoiceOver on macOS does announce it as a non-standard remediation of invalid code. Testing with VoiceOver alone will not catch this bug.


The Three Attributes: When to Use Each

aria-label

Use aria-label when there is no visible text that can serve as the name - icon-only buttons, generic "Read more" links that need disambiguation, or landmark regions that appear more than once on a page.

<!-- Icon button with no visible text -->
<button aria-label="Close dialog">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

<!-- Two nav landmarks on the same page -->
<nav aria-label="Primary">...</nav>
<nav aria-label="Footer">...</nav>

<!-- Generic "Read more" link made specific -->
<a href="/articles/eaa-fines" aria-label="Read more about EAA fines">
  Read more
</a>

The trap: aria-label overrides visible text. If a button reads "Submit" and you add aria-label="Submit your application form", the screen reader announces the longer string while the sighted user sees "Submit". A voice-control user who says "click Submit" may not match. WCAG 2.5.3 requires the visible text to appear within the accessible name - so if you must add context, ensure the visible string is a substring of the aria-label value.

The second trap: aria-label strings are not automatically translated. When a page is localised, hardcoded aria-label values in templates are routinely forgotten, leaving French or German users with English accessible names.

aria-labelledby

Use aria-labelledby to reference visible text that already exists on the page. It supports multiple ids; the browser concatenates the referenced strings in order.

<!-- Dialog labelled by its visible heading -->
<div role="dialog" aria-labelledby="dialog-title" aria-modal="true">
  <h2 id="dialog-title">Confirm deletion</h2>
  ...
</div>

<!-- Input labelled by two separate visible strings -->
<span id="qty-label">Quantity</span>
<span id="item-name">Blue Linen Shirt</span>
<input type="number" aria-labelledby="qty-label item-name" />
<!-- Announced as: "Quantity Blue Linen Shirt, spin button" -->

aria-labelledby beats aria-label in the computation algorithm. It also keeps the accessible name in sync with the visible UI automatically - if the heading text changes, the accessible name changes too. Prefer it over aria-label whenever visible text is available.

aria-describedby

aria-describedby provides supplementary information - it is not a substitute for an accessible name. Screen readers announce the description after the name and role, typically with a brief pause.

<label for="password">Password</label>
<input
  type="password"
  id="password"
  aria-describedby="pw-hint pw-error"
/>
<p id="pw-hint">Must be at least 12 characters.</p>
<p id="pw-error" role="alert">Password is too short.</p>

A common mistake is using aria-describedby as the sole labelling mechanism. If the <label> is removed and only aria-describedby remains, the input has no accessible name - a 4.1.2 failure. The description supplements; it does not replace.

star Important

aria-describedby is not a name source. The AccName algorithm uses aria-describedby only for the accessible description, not the accessible name. An element with only aria-describedby and no other naming mechanism has no accessible name and fails WCAG 4.1.2.


The Failure Patterns Behind the 2026 Numbers

Empty links and empty buttons

Empty links appeared on 46.3% of home pages; empty buttons on 30.6% - up from 29.6% in 2025. These are accessible-name failures. The most common causes:

  • Icon-only controls where the SVG or image has no alt and the button has no aria-label.
  • Link-wrapped images where the <img> has an empty alt="" and the <a> has no other text.
  • Sprite images used as button backgrounds, invisible to the accessibility tree.
<!-- ❌ Empty button: SVG has no title, button has no aria-label -->
<button>
  <svg viewBox="0 0 24 24"><path d="..."/></svg>
</button>

<!-- ✅ Fixed: label the button, hide the decorative SVG -->
<button aria-label="Search">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <path d="..."/>
  </svg>
</button>

The role="menu" problem

5.7% of home pages used role="menu", and 22% of those introduced accessibility barriers due to missing ARIA menu markup and interactions. The root cause is a category error.

role="menu" is for application menus - the File/Edit/View dropdowns in a desktop-style application. It is not for site navigation. When screen readers encounter role="menu", they enter an interaction mode that expects arrow-key navigation between menuitem children. If that keyboard behaviour is not implemented in JavaScript - and it rarely is in site nav - the user hears "menu" and then nothing works as expected.

The correct pattern for site navigation is a <nav> landmark containing a <ul> of links. For a disclosure-style dropdown, use a <button> with aria-expanded and aria-controls, and a <ul> of links - no role="menu" required.

<!-- ❌ Wrong: role="menu" on site navigation -->
<nav>
  <ul role="menu">
    <li role="menuitem"><a href="/products">Products</a></li>
    <li role="menuitem"><a href="/pricing">Pricing</a></li>
  </ul>
</nav>

<!-- ✅ Right: semantic nav with disclosure button -->
<nav aria-label="Primary">
  <ul>
    <li><a href="/products">Products</a></li>
    <li>
      <button aria-expanded="false" aria-controls="solutions-menu">
        Solutions
      </button>
      <ul id="solutions-menu" hidden>
        <li><a href="/enterprise">Enterprise</a></li>
        <li><a href="/smb">SMB</a></li>
      </ul>
    </li>
  </ul>
</nav>

aria-hidden hiding focusable content

Home pages averaged 23.3 aria-hidden="true" attributes - up 30% from 18 in 2025, and up over 250% since 2020. aria-hidden="true" removes an element from the accessibility tree. Applied to a container that holds focusable elements, it creates a keyboard trap: the element receives focus but is invisible to the screen reader. The fourth rule of ARIA is explicit: do not hide focusable elements.

<!-- ❌ Wrong: focusable link inside aria-hidden container -->
<div aria-hidden="true">
  <a href="/help">Help</a>
</div>

<!-- ✅ Right: hide only decorative content; keep interactive
     elements in the tree, or use display:none / inert -->
<div aria-hidden="true">
  <img src="decorative-swirl.svg" alt="" />
</div>

Localisation of aria-label strings

aria-label values live in markup or JavaScript, not in translation files. When a product is localised, these strings are routinely missed. The result: a French-language page where every icon button is announced in English. There is no automated test that catches this - it requires a manual review of each locale.


When NOT to Reach for ARIA

A short checklist for the most common situations:

  • You need a button. Use <button>. Not <div role="button">.
  • You need a link. Use <a href>. Not <span role="link">.
  • You need a checkbox. Use <input type="checkbox">. Not <div role="checkbox">.
  • You need to label a form field. Use <label for>. Not aria-label on the input.
  • You need to mark up site navigation. Use <nav> and <ul>. Not role="menu".
  • You need to hide a decorative image. Use alt="". Not aria-hidden="true" on the <img> (though aria-hidden on a container of decorative content is fine).
  • You need to describe a field's constraints. Use aria-describedby pointing at visible hint text - but make sure the field also has an accessible name from a <label>.

How to Verify: Accessibility Tree First, Screen Reader Second

Automated tools can tell you whether an accessible name exists. They cannot tell you whether it is meaningful. "Button" is a name; it is also useless. Verification requires two steps.

Step 1: Inspect the accessibility tree.

In Chrome DevTools, open the Elements panel, select an element, and open the Accessibility tab. The computed accessible name, role, and description are shown directly. In Firefox, the Accessibility panel provides the same view. Look for:

  • Name: is it present? Is it descriptive?
  • Role: does it match what the element is supposed to be?
  • Description: is aria-describedby wired to the right element?

Step 2: Test with a real screen reader.

Browser devtools show what the accessibility tree exposes. A screen reader shows what a user actually hears. NVDA with Firefox and JAWS with Chrome cover the majority of Windows screen reader users. VoiceOver on macOS is essential for Safari testing. Navigate by tab and by element type (button list, link list, form controls). If a name sounds wrong in context, it is wrong.

85.9% of screen reader survey respondents said better web sites would improve accessibility more than better assistive technology, according to the WebAIM Screen Reader User Survey #10 (1,539 respondents, December 2023-January 2024). The second most problematic issue reported: interactive elements like menus, tabs, and dialogs not behaving as expected. Third: links or buttons that do not make sense. Both are ARIA-implementation failures - and both are detectable with a ten-minute screen reader walkthrough.


The EAA Stake: Level A Failures Are the Easiest to Demonstrate

An icon button with no accessible name fails WCAG 2.1 Success Criterion 4.1.2 Name, Role, Value at Level A. An empty link fails 2.4.4 Link Purpose at Level A. A form input with no label fails 3.3.2 Labels or Instructions at Level A.

Under the European Accessibility Act, WCAG 2.1 AA via EN 301 549 is the operative technical baseline. EN 301 549 v3.2.1 is the version currently cited as harmonised in the Official Journal; draft v4.1.0 was published in November 2025, with v4.1.1 (aligning to WCAG 2.2) expected to be cited later in 2026 - though that timing is not yet settled.

Level A failures are the easiest thing for a market surveillance authority or a complainant to demonstrate. They require no expert judgment about colour contrast ratios or cognitive load. A screen reader user navigates to an icon button, hears nothing, and screenshots the accessibility tree. That is the evidence.

Missing form input labels appeared on 51% of home pages in 2026, up from 48.2% in 2025; 33.1% of form inputs were not properly labelled. These are not edge cases. They are the baseline state of the web, and they are exactly what EAA enforcement will surface first.

ARIA labels are a legitimate and necessary tool for the cases where native HTML cannot provide the semantics - custom widgets, dynamic regions, icon-only controls. Used correctly, they close real gaps. Used as a shortcut around native HTML, or generated automatically without review, they create new ones. The first rule of ARIA is not a suggestion.



Further reading