/ โ† Accessibility Fixes / aria-label Not Working
In this guide
  1. What aria-label actually does
  2. Why aria-label is ignored
  3. How to see what the browser is announcing
  4. The fixes in code
  5. Screen reader differences on Windows
  6. aria-label and translation by locale
  7. The fix, step by step
  8. Edge cases worth knowing
  9. Keeping your labels working
  10. Questions and answers

What aria-label actually does

Every interactive element and many structural ones have an accessible name, the text a screen reader speaks and a voice control user says to activate it. Browsers work the name out in a fixed order and use the first source they find:

  1. aria-labelledby, pointing at the id of other elements.
  2. aria-label, a text string on the element itself.
  3. The native source: the <label> of a form field, the alt of an image, the <legend> of a fieldset, the <caption> of a table.
  4. The element's own text content, but only for roles that take their name from content, such as buttons, links, headings and table cells.
  5. The title attribute or a placeholder, as a last resort.

Two consequences explain most problems. First, aria-label replaces anything lower in the list, so a button with visible text Buy and aria-label="Add to basket" is announced as Add to basket. Second, aria-label is invisible. It never draws anything on screen and it is not a tooltip, which is why people ask why it is not showing.

๐Ÿ’ก The first rule of ARIA is to use a native HTML element with the meaning you need where one exists. A real <button> with visible text needs no aria-label at all.

Why aria-label is ignored

Where you put itWhat happensWhy
<div> or <span> with no roleIgnored by most screen readers, or read inconsistentlyThese have the generic role, and ARIA 1.2 prohibits naming generic elements
<p>, <strong>, <em>, <code>IgnoredParagraph and text-level roles cannot be named either
<a> with no hrefIgnored, and the link is not focusableWithout href it is not a link; it has the generic role
Element with role="presentation" or role="none"IgnoredThe role removes the element's meaning
Inside aria-hidden="true"Nothing is readThe whole subtree is removed from the accessibility tree
Element that also has aria-labelledbyThe aria-label is not usedaria-labelledby comes first in the name order
On a child span inside a buttonIgnored; the button is named from its textThe span is generic, so its label does not count
aria-label="" or a typo such as aria-lableIgnoredAn empty or unknown attribute is skipped
ariaLabel in JSXNot rendered as an attributeReact expects the hyphenated name aria-label

Where it works reliably: buttons, links with an href, form fields, images and SVGs with role="img", landmarks such as <nav>, <section> and <form>, dialogs, and any element given a role that supports a name, such as button, group, region or img.

How to see what the browser is announcing

Do not guess from the source. Ask the browser what name it calculated.

To list every aria-label on a page and the role of its element, paste this into the console:

document.querySelectorAll('[aria-label]').forEach(el => {
  const role = el.getAttribute('role') || el.tagName.toLowerCase();
  const hidden = el.closest('[aria-hidden="true"]') ? ' (inside aria-hidden)' : '';
  console.log(role, '|', el.getAttribute('aria-label') + hidden);
});

Anything listed as div, span, p or a without an href is a candidate for the fixes below. Then confirm with a real screen reader: NVDA is free on Windows, Narrator is built in (Ctrl+Windows+Enter), and VoiceOver is built into Mac and iPhone.

The fixes in code

A clickable div with aria-label

Swap it for a real button. You get the role, keyboard support and focus for free, and the label then works:

<!-- Before: not announced, not focusable -->
<div class="close" aria-label="Close" onclick="closeMenu()"><svg>...</svg></div>

<!-- After -->
<button type="button" class="close" aria-label="Close menu">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

A div that labels a group or area

If the div is a container you want named, give it a role that accepts a name, or use the right element:

<div role="group" aria-labelledby="ship-title">
  <h3 id="ship-title">Delivery options</h3>
  ...
</div>

<section aria-label="Customer stories">...</section>

Extra context for a span or text

Text elements cannot be named, so put the extra words in the text itself and hide them visually:

<span class="price">&pound;12<span class="visually-hidden"> per month</span></span>

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

A button with visible text

Either drop the aria-label and let the text name the button, or make sure the label starts with the visible words. WCAG 2.5.3 Label in Name requires the accessible name to contain the visible text, so voice control users who say click Buy can still press it:

<!-- Fails 2.5.3 -->  <button aria-label="Add to basket">Buy</button>
<!-- Passes -->      <button aria-label="Buy Example Bakery sourdough loaf">Buy</button>

Screen reader differences on Windows

On Windows, three screen readers are common: NVDA, JAWS and the built-in Narrator. They read the same accessibility tree from the browser, but they choose differently what to say, which is why a label can seem to work on one and not another.

The fix for cross-reader differences is always the same: put the label on an element whose role supports it, and prefer visible text. If the name shows correctly in the DevTools Accessibility pane, the browser is doing its job, and a remaining difference is down to how a screen reader presents that role.

aria-label and translation by locale

An aria-label is a fixed string. It does not change by locale on its own: if your template says aria-label="Close", every visitor gets Close, whatever language the page is in. Automatic page translation tools may also skip or handle attribute text inconsistently, while they reliably translate visible text. So labels need to be translated by you, in the same way as the rest of your interface text.

The fix, step by step

Step 1

Check the computed name in DevTools

Inspect the element in Chrome or Edge and open the Accessibility pane. Read the Role and the Name under Computed Properties. If the role is generic, the label is on an element that cannot be named. If the name comes from another source, such as aria-labelledby or the content, your aria-label lost the priority order. Note the result for each failing element before you change anything, so you can compare afterwards.

Step 2

Replace clickable divs and spans with buttons

Wherever a div, span or link without an href acts as a control, change it to a real button element with type set to button, or to a link with a real href if it navigates. Move the aria-label onto the new element and delete any tabindex and key handlers you added to fake one. Tab to it and confirm it receives focus, activates with Enter and Space, and the screen reader reads its name.

Step 3

Give named containers a proper role

For a container that genuinely needs a name, such as a group of related options or a page area, use a section, nav or form element, or add role set to group or region. Prefer aria-labelledby pointing at a visible heading, so sighted and screen reader users see the same words. Check the Accessibility pane now shows the role and the name, and that the area appears in the screen reader's landmarks list.

Step 4

Move extra context into visually hidden text

Where you used aria-label on a span, paragraph or price to add context, delete it and put the extra words inside the element in a visually hidden span instead. That text is part of the content, so every screen reader reads it and translation tools translate it. Add the visually hidden CSS class to your stylesheet once. Read the line with a screen reader and confirm it now includes the hidden words.

Step 5

Align button labels with visible text

For buttons and links that show text, either remove the aria-label so the visible text is the name, or rewrite it so it starts with exactly the visible words. This meets WCAG Label in Name and lets voice control users activate the control by saying what they see. For icon-only buttons, keep the aria-label and hide the icon with aria-hidden. Test by reading the computed name against the visible text.

Step 6

Remove conflicts that override the label

Search the templates for elements that have both aria-label and aria-labelledby, labels on children of buttons, empty aria-label values, misspellings and ariaLabel in JSX. Remove whichever source you do not want. Also check that no parent has aria-hidden set to true and no element has role set to presentation. Rerun the console snippet and confirm each remaining label sits on an element with a role that supports a name.

Step 7

Translate labels and set the page language

Pass every aria-label string through your translation system, the same as visible text: the t filter in Shopify Liquid, esc_attr__ in WordPress, or your app's i18n function. Make sure each language version has the correct lang attribute on the html element. Switch to a second language and check in the Accessibility pane that names are translated, then listen with a screen reader to confirm the correct voice is used.

Step 8

Test on NVDA, Narrator and VoiceOver

Tab through the fixed controls with NVDA and Narrator on Windows and VoiceOver on Mac or iPhone, then read the page with the arrow keys in browse mode. Each control should announce its role and name once. If the DevTools name is correct but one screen reader still differs, check you are not relying on a label on a non-interactive element. Finally, run the accessibility audit to catch any remaining unnamed controls.

Edge cases worth knowing

Keeping your labels working

Add aria-labels in components, not page by page, so the right element and role are fixed once. Run the accessibility audit after theme or plugin updates, because a new version can change a button into a div. Keep the console snippet above in your test notes, and check any new icon-only control in the Accessibility pane before release. The wider rules for labels are in fixing ARIA labels, and invalid or misused attributes are covered in fixing ARIA errors.

Questions and answers

1. Why is aria-label not working on my div?

A plain div has the generic role, and ARIA 1.2 does not allow generic elements to be named, so most screen readers ignore an aria-label on it. The same applies to span, p and a link without an href. If the div is a control, change it to a button element. If it is a container that needs a name, use section, nav or form, or add a role such as group or region. If you only need extra words read, put them in visually hidden text instead.

2. Why is aria-label not working on my button?

It usually is working, but in a way you did not expect, or it is on the wrong element. On a real button, aria-label replaces the visible text as the name, so the screen reader reads the label, not the text. If it is ignored, check whether it is on a span inside the button, whether aria-labelledby is also present, whether a parent has aria-hidden set to true, and whether the button is actually a div. The Chrome DevTools Accessibility pane shows which source won.

3. Why is my aria-label not showing on the page?

aria-label is never shown on screen. It only provides a name to assistive technology such as screen readers and voice control, and it does not create a tooltip on hover. If you want sighted users to see a label, use visible text or a proper tooltip component. The title attribute shows a hover tooltip, but not to keyboard or touch users, so it is a poor replacement. For icon buttons, many sites show a visible text label next to the icon as well as the accessible name.

4. Why does aria-label work in one screen reader but not another on Windows?

Different screen readers present the same accessibility tree in slightly different ways. NVDA, JAWS and Narrator all read names on buttons, links, form fields and landmarks reliably, but they vary when the label is on an element that should not be named, such as a div or span, or on a non-interactive container read in browse mode. Move the label onto an element whose role supports a name. If the name then looks right in DevTools, the remaining differences are usually just verbosity settings.

5. Does aria-label change by locale automatically?

No, aria-label is a fixed text string and does not change with the visitor's language. If your template hard-codes an English label, every language version of the page gets the English word. Automatic translation tools are also less dependable with attribute text than with visible text. Translate labels through your theme or app translation system, prefer visible or visually hidden text that is translated with the page, and set the correct lang attribute so screen readers use the right voice and pronunciation.

6. Should I use aria-label or aria-labelledby?

Use aria-labelledby when the name already exists as visible text on the page, such as a heading above a group of options, because it keeps the visible and spoken names the same and follows translations automatically. Use aria-label when there is no visible text to point to, such as an icon-only close button. If both are present, aria-labelledby wins and the aria-label is ignored. Where a native label element, alt attribute or visible button text can do the job, use those instead of either.

7. Does aria-label help SEO?

No, aria-label is not a ranking factor, and Google does not treat it as visible content. Its job is accessibility. Some search and AI crawlers may read attribute text, but you should never put keywords in aria-labels for that reason, because it makes screen reader output longer and confusing. Visible text, proper headings and descriptive link text help both people and search engines. A correct accessible name on icon buttons and links does improve accessibility audits, which matter for compliance and usability.

Find buttons and links with no accessible name

The accessibility audit lists controls with missing or ignored names, ARIA attributes on elements that do not support them and icon buttons with no label, so you can fix them at the template.

Open Accessibility Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All Accessibility Fixes  ·  Fixing ARIA Labels  ·  Fixing ARIA Errors  ·  The Title Attribute  ·  Fixing Keyboard Navigation  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.