Links and buttons Rule

ARIA buttons, links and menu items need a name aria-command-name

When you give an element role="button", role="link" or role="menuitem", you are promising assistive technology that it is a control. A control needs a name. A div with a role and only an icon inside has none, so a screen reader announces just 'button' or 'menu item'. Give it visible text, an aria-label, or point aria-labelledby at text nearby.

Websight reports this as ARIA commands must have an accessible name

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.

Broken

Announced: button. Then: button. The icons draw a printer and an envelope, but the roles carry no name.

Fixed

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
Broken
<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>
Fixed
<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

  1. In Chrome DevTools, select the element and open the Accessibility pane. The Name row should not be empty.
  2. 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.
  3. Tab to the control with NVDA or VoiceOver running. You should hear the name, then the role.
  4. 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

Before
<div role="button" tabindex="0" class="icon print"></div>
After
<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

Before
<li role="menuitem" tabindex="-1" class="icon-download"></li>
After
<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

Before
<h3 id="minutes-sep">Minutes, September</h3>
<span role="link" tabindex="0" class="arrow"></span>
After
<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:

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.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.