ARIA links, buttons, and menu items need accessible name
Last updated:
Related Guides
ARIA links, buttons, and menu items must have an accessible name
Every element with role=link, role=button, or role=menuitem must expose a clear accessible name.
This often fails on custom controls built from div/span, icon-only buttons, and ARIA menus.
Missing names block screen reader and speech users from understanding or activating controls.
Why It Matters
A control without a name is invisible in purpose to screen readers. Users hear "button" or "link" with no description and cannot decide what it does.
Speech input users rely on the label to issue commands (e.g., "Click Save"). If the label is missing or does not match the visible text, voice activation fails.
Clear names also help users with cognitive disabilities by reducing ambiguity when navigating lists of links or buttons.
Common Causes
- Using div/span with ARIA roles but no
aria-label,aria-labelledby, or visible text. - Empty or whitespace-only
aria-labelvalues. aria-labelledbypointing to an ID that does not exist or that references hidden/empty elements.- Icon-only buttons/links where the SVG has
aria-hiddenbut no alternative text is provided. - Relying only on the title attribute for naming (inconsistent announcement across platforms).
- Visible label that differs from the programmatic name, breaking voice control (violates Label in Name).
How to Fix
- Prefer native controls:
- Use
<a href>with meaningful link text. - Use
<button>with visible, descriptive text.
- Use
- Provide a programmatic name when there is no visible text:
- Add
aria-labelwith concise, specific text (e.g., "Play video", "Open cart"). - Or use
aria-labelledbyto reference existing visible text near the control.
- Add
- Keep names descriptive and task-focused:
- Links: describe the destination or content ("Pricing", "Download report"). Avoid "Click here".
- Buttons: describe the action ("Submit order", "Add to cart").
- Validate references:
- Ensure every
aria-labelledbypoints to one or more valid element IDs that contain useful text.
- Ensure every
- Align visible text with the accessible name (WCAG 2.5.3 Label in Name):
- If users see "Save", include "Save" in the accessible name (not "Commit").
- Recommendation: Avoid title-only labeling:
- Some AT announce it; others do not. Prefer visible text,
aria-labelledby, oraria-label.
- Some AT announce it; others do not. Prefer visible text,
- For ARIA menus:
- Each element with role=menuitem, menuitemcheckbox, or menuitemradio needs a clear name via text content or ARIA naming.
How to Test
Keyboard check
- Tab through links, buttons, and menu items. Each control should receive focus and be reachable (focus confirms it’s operable; continue with name checks below).
Screen reader check
- Desktop (NVDA/JAWS/VoiceOver):
- Move focus to each control and listen for a clear name and role (e.g., "Save, button").
- Use the Links List and Buttons List to verify each entry has a meaningful name.
- Verify visible labels match the spoken name for voice control compatibility.
Mobile/touch check
- iOS/Android with screen reader enabled: swipe to each control and confirm a clear name is announced.
- If using voice control, try activating by saying the visible label (Label in Name).
Developer/inspection check
- Use browser devtools Accessibility pane to confirm the computed Name and Role.
- Ensure no empty
aria-labeland no brokenaria-labelledbyreferences.
Good Example
<!-- Native button with visible label -->
<button type="submit">Submit order</button>
<!-- Icon-only button named with aria-label -->
<button class="icon-only" aria-label="Play video">
<svg aria-hidden="true" focusable="false"><!-- icon --></svg>
</button>
<!-- Link with referenced label -->
<p id="report-label">Download Q4 report (PDF)</p>
<a href="/files/q4-report.pdf" aria-labelledby="report-label"> </a>
<!-- ARIA menu with named menuitem -->
<div role="menu" aria-label="User menu">
<div role="menuitem"><span>Profile</span></div>
<div role="menuitem" aria-labelledby="logout-text">
<span id="logout-text">Sign out</span>
</div>
</div>Bad Example
<!-- No name at all -->
<div role="button"></div>
<!-- Empty aria-label -->
<button aria-label=" ">
<svg aria-hidden="true"></svg>
</button>
<!-- Broken aria-labelledby reference -->
<div role="menuitem" aria-labelledby="missing-id"></div>
<!-- Non-descriptive name -->
<a href="/pricing" aria-label="Link">
<svg aria-hidden="true"></svg>
</a>Quick Checklist
- Every role=link, role=button, and role=menuitem has a non-empty accessible name.
- Name is provided by visible text,
aria-labelledby, oraria-label(in that preference order). - Names are specific and action/destination oriented (no "Click here").
aria-labelledbyIDs exist and reference elements with meaningful text.- Visible label text appears in the programmatic name (Label in Name).
- Icon-only controls include a concise
aria-label. - Avoid title-only naming; use it only as a fallback if nothing else is possible.
- Confirm names via screen reader and devtools computed Name.