sfw/fix
label-content-name-mismatch medium

Visible text must be part of the accessible name

An aria-label overrides the visible button text, so voice-control users can't activate the control by saying what they see (WCAG 2.5.3).

What you see

Elements must only use supported ARIA attributes
Text inside the element is not included in the accessible name
<button aria-label="OK">Submit</button>

What’s actually happening

A button reads "Submit" on screen, but its accessible name is "OK" because an aria-label clobbered the visible text. Someone using Dragon or Voice Control says "click Submit" and nothing happens — the speech engine matches spoken words against the accessible name, and "Submit" isn't in it. The control still works fine with a mouse and even with a screen reader, which is why this slips through. It only bites voice-input users, and it bites them hard: the thing they can see is the one phrase that won't trigger it.

Common causes

  • An aria-label was added for screen readers ("Submit your order") that drops or rewords the visible word ("Submit"), so the spoken label no longer contains the on-screen text
  • A translation or design tweak changed the visible label but left the old aria-label string behind
  • An icon-plus-text button has aria-label set to only the icon's meaning ("Search") while the visible text says something longer ("Search products")
  • aria-labelledby points at a different element than the one holding the visible text, so the computed name diverges from what's rendered
  • A component library auto-generates aria-label from a prop that isn't the same string shown in the slot/children

How to fix it

  1. Make the accessible name start with the visible textWCAG 2.5.3 only requires the visible label to be contained in the accessible name, at the start. So <button aria-label="Submit your order">Submit</button> passes — "Submit" leads the accessible name. <button aria-label="Order now">Submit</button> fails. Match the leading words to what's printed on the control.
  2. Drop the aria-label entirely when the visible text is already enoughIf the button text fully describes the action, you don't need aria-label at all — the text content becomes the accessible name on its own. Removing it is the cleanest fix and kills a whole class of drift between the two strings. Reserve aria-label for icon-only controls with no text node.
  3. Point aria-labelledby at the visible text node, not a hidden duplicateIf you must compose the name from elsewhere, include the id of the element that holds the on-screen words: aria-labelledby="visibleSpan extraContext". Order matters — list the visible-text id first so the name begins with what the user sees and reads.
  4. Keep purely visual punctuation out of the comparisonaxe trims trailing whitespace and is reasonably tolerant of casing, but a label like "Next ›" vs aria-label "Next page" still passes because "Next" leads. Don't pad the accessible name with words before the visible text ("Go to Next") — that's the pattern that fails.
  5. Test by voice, not just by scannerTurn on macOS Voice Control or Windows Speech Recognition and say "click <the visible word>". If the control activates, the name contains the label. axe catches the obvious mismatches, but a real voice command is the ground truth for 2.5.3.

Stop it recurring

When you set aria-label on a control that also shows text, make the label begin with that exact visible text — or don't set aria-label at all.

Related errors