The problem
ARIA labels give assistive technology an “accessible name”—the text a screen reader announces for a control. Icon-only buttons (a bare hamburger, a trash can, a magnifying glass) are the classic offender: visually obvious, but announced as just “button.” The first rule of ARIA is to use native HTML where possible, but when you build custom controls or icon buttons, a correct aria-label (WCAG 4.1.2) is what makes them usable.
The fix
<button><svg>...</svg></button> <!-- icon-only, no label -->
<div role="dialog">...</div> <!-- no dialog title -->
<nav>...</nav> <!-- multiple navs, no differentiation --><button aria-label="Close dialog"><svg aria-hidden="true">...</svg></button>
<div role="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirm deletion</h2>
</div>
<nav aria-label="Main navigation">...</nav>
<nav aria-label="Breadcrumb">...</nav>Step by step
- Every icon-only button must have aria-label or aria-labelledby.
- Dialogs/modals need aria-labelledby pointing to the visible heading.
- When there are multiple
<nav>landmarks, give each an aria-label. - Add
aria-hidden="true"to decorative SVGs/icons so screen readers skip them.
Common mistakes
- Icon-only buttons or links with no aria-label.
- Decorative SVGs left without
aria-hidden="true", cluttering the screen reader. - Multiple
<nav>or<section>landmarks with no distinguishing label. - Overriding a visible label with a different aria-label, which confuses voice-control users.
How to test for it
- Tab to each icon button in a screen reader and confirm it announces a clear name.
- Inspect the accessibility tree in DevTools—every control should have a non-empty name.
- Run an automated scan for controls missing an accessible name.
In your framework
// Icon button pattern
<button aria-label="Delete item">
<TrashIcon aria-hidden="true" />
</button>Questions
What's the difference between aria-label and aria-labelledby?
aria-label provides an inline string. aria-labelledby references another element's text by ID — preferred when a visible label already exists.
Find it on your site.
Scan a page and see every place this issue appears, with the element and the fix.
Scan your site