Who it affects
A resident who is blind, reading the parish council's agenda page reaches a custom Print control and hears only 'button', with no clue that it prints the agenda.
Someone using voice control cannot name the custom items in a Documents menu, so the menu is unusable by voice.
Someone using a switch to step between controls hears nameless controls and has to activate each one to find out what it does.
Broken versus fixed
Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.
Announced: button. Then: button. The icons draw a printer and an envelope, but the roles carry no name.
Announced: Print agenda, button. Then: Email the clerk, button. Real button elements also handle Enter and Space for free.
Show the markup behind both examples
<style>body{font-family:system-ui;margin:0;padding:16px}.bar{display:flex;gap:10px;align-items:center}.icon{width:36px;height:36px;border:1px solid #9aa5b1;border-radius:6px;background:#fff;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.icon:focus{outline:3px solid #1b5e9e}.icon span{width:16px;height:12px;background:#1f2937;border-radius:2px}.icon.mail span{background:#e07a1f}</style>
<p style="margin:0 0 8px"><strong>Parish council agenda, 4 November</strong></p>
<div class="bar">
<div role="button" tabindex="0" class="icon print"><span></span></div>
<div role="button" tabindex="0" class="icon mail"><span></span></div>
</div>
<style>body{font-family:system-ui;margin:0;padding:16px}.bar{display:flex;gap:10px;align-items:center}.icon{width:36px;height:36px;border:1px solid #9aa5b1;border-radius:6px;background:#fff;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;padding:0}.icon:focus{outline:3px solid #1b5e9e}.icon span{width:16px;height:12px;background:#1f2937;border-radius:2px}.icon.mail span{background:#e07a1f}</style>
<p style="margin:0 0 8px"><strong>Parish council agenda, 4 November</strong></p>
<div class="bar">
<button type="button" class="icon print" aria-label="Print agenda"><span aria-hidden="true"></span></button>
<button type="button" class="icon mail" aria-label="Email the clerk"><span aria-hidden="true"></span></button>
</div>
Test it by hand in two minutes
- In Chrome DevTools, select the element and open the Accessibility pane. The Name row should not be empty.
- In the Elements panel press Cmd+F or Ctrl+F and search for role="button", then role="link", then role="menuitem". For each match, find the text, aria-label or aria-labelledby that names it.
- Tab to the control with NVDA or VoiceOver running. You should hear the name, then the role.
- Ask whether a real button, a or select element would do the same job. Native elements get keyboard support and naming without any extra work.
The fix
<div role="button" tabindex="0" class="icon print"></div>
<button type="button" class="icon print" aria-label="Print agenda"></button>
The best fix is usually a real button, which also handles Enter and Space. If the role has to stay, add aria-label or visible text.
Menu item with only an icon
<li role="menuitem" tabindex="-1" class="icon-download"></li>
<li role="menuitem" tabindex="-1">Download minutes (PDF)</li>
Visible text names the item and helps sighted people too.
Custom link named by a nearby heading
<h3 id="minutes-sep">Minutes, September</h3>
<span role="link" tabindex="0" class="arrow"></span>
<h3 id="minutes-sep">Minutes, September</h3>
<span role="link" tabindex="0" class="arrow" aria-labelledby="minutes-sep"></span>
aria-labelledby reuses words already on the page, so the two cannot drift apart. A real a element with an href would be better still.
Common mistakes
- Adding the role without tabindex="0", so the control cannot be reached by keyboard even once it has a name.
- Relying on a title attribute for the name.
- Using a CSS background image or an icon font and assuming the picture speaks for itself.
- Naming the control but forgetting to handle Enter and Space, which native buttons do on their own.
WCAG criteria this rule maps to
axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:
- 4.1.2 Name, Role, Value (level A). Official W3C text.
The scanner can see an element with role button, link or menuitem that has no text content, aria-label or aria-labelledby. It cannot tell whether a name is meaningful, and it does not check that the custom control works with a keyboard. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.
Related rules
button-name
A button needs a name that assistive technology can announce.
A
Links must have text a screen reader can announce
link-name
Every link needs text that a screen reader can announce and a voice control user can say.
A
ARIA input fields must have an accessible name
aria-input-field-name
When a div or span is given a form role such as textbox, combobox, listbox, slider or spinbutton, assistive technology treats it as a field.
A
ARIA toggle fields must have an accessible name
aria-toggle-field-name
Elements with role="switch", role="checkbox", role="radio", role="menuitemcheckbox" or role="menuitemradio" are toggles: they are on or off, checked or not.