( Robust / WCAG 4.1.2 )
ARIA command has no accessible name
What is this issue?
An element carrying role="button", role="link", or role="menuitem" (ARIA’s three command roles, so named because each one triggers an action rather than displaying static content) has no accessible name, the text a screen reader announces to identify an element. It comes from the first source that applies, in order: aria-labelledby, aria-label, visible text content, then other fallbacks specific to the element type.
None of those sources resolve to anything. The element has no text content, no aria-label, and no aria-labelledby pointing at text elsewhere on the page. Its role is announced correctly, but the action it performs is not.
Why does this matter?
A command exists to do something when activated: close a panel, add an item to a cart, open a submenu. If the only information a screen reader can announce is the role, the user has to activate it blind and observe the result to learn what it did, which is a poor substitute for knowing in advance.
This shows up most often on icon-only controls: a toolbar built from <div role="button"> elements wrapping SVG icons, with no text anywhere in the markup describing “bold,” “undo,” or “close.” Sighted users read the icon visually. Screen reader users get “button” repeated once per icon, indistinguishable from every other button in the same toolbar.
Who is affected?
- Screen reader users: hear a bare role (“button,” “link,” “menu item”) with no indication of the action, and have to activate each control speculatively to learn what it does.
- Voice control users: target a command by speaking its visible or accessible name, such as “click Undo.” With no name to match, the control can’t be addressed by voice at all, regardless of how clearly its icon reads visually.
What users experience
Diego uses JAWS on Windows to draft documents in a browser-based editor. He tabs into the formatting toolbar above the text area and JAWS announces “button” six times in a row as he moves through bold, italic, underline, and three more icon-only controls, giving him no way to tell which one does what without leaving the toolbar to check the visual layout with a sighted colleague first.
How do I fix it?
Give the command visible text describing the action, since that satisfies the accessible name for every screen reader with no ARIA required at all. This works because visible text is the most broadly supported naming source in the accessible name computation; it needs no extra attribute and stays in sync with what sighted users see by construction.
When the design requires an icon-only control with no visible text, add aria-label with a short, verb-first description of the action (“Undo,” “Close menu,” “Add to cart”). This works because aria-label supplies a name directly to assistive technology without changing what’s rendered on screen, so the compact visual design stays intact.
Where the underlying element is a div or span with role="button" added by hand, consider switching to a native <button> when nothing else about the design depends on the div. A native button gets keyboard focus, Enter/Space activation, and the command role for free: the custom role only exists to retrofit behavior HTML already provides.
Code Examples
<div class="toolbar">
<div role="button" onclick="toggleBold()"><svg><!-- bold icon --></svg></div>
<div role="button" onclick="toggleItalic()"><svg><!-- italic icon --></svg></div>
</div><!-- Method 1: native button (preferred where the design allows it) -->
<div class="toolbar">
<button aria-label="Bold" onclick="toggleBold()"><svg aria-hidden="true"><!-- bold icon --></svg></button>
<button aria-label="Italic" onclick="toggleItalic()"><svg aria-hidden="true"><!-- italic icon --></svg></button>
</div>
<!-- Method 2: role="button" kept, aria-label added -->
<div class="toolbar">
<div role="button" tabindex="0" aria-label="Bold" onclick="toggleBold()"><svg aria-hidden="true"><!-- bold icon --></svg></div>
</div>Both fixes give each command a specific aria-label naming the action instead of leaving the icon as the only signal. aria-hidden="true" on the inner SVG stops the icon’s own markup from adding redundant or conflicting text to the accessible name computation. Method 1 also restores native keyboard behavior the div version never had.
Framework Examples
A shared icon-button component is the most common source of this rule’s failures in component-driven UIs: one <IconButton icon={...} /> component used across a whole toolbar produces every one of this rule’s violations at once if the component doesn’t require a name. Make the label a required prop instead of an optional one, so a missing name fails at build time instead of shipping silently.
function IconButton({ icon, label, onClick }) {
return (
<button aria-label={label} onClick={onClick}>
<span aria-hidden="true">{icon}</span>
</button>
);
}
// TypeScript: label: string (not label?: string) turns a missing name
// into a compile error instead of a silent accessibility bug.
Requiring label at the type level catches the failure before the component ever renders, which scales better than manually auditing every call site for a forgotten aria-label.
Common Mistakes
Mistake: “The icon is self-explanatory, so it doesn’t need a name.” An icon that reads clearly to a sighted user carries no information at all to a screen reader unless it’s paired with text: aria-label, visible text, or a <title> inside an SVG. Visual clarity and accessible-name presence are two independent things.
Mistake: “I added alt to the icon, so the button has a name.” The alt attribute belongs to <img> elements. An inline SVG icon has no alt attribute at all; it needs its own <title> element or aria-label on the SVG, or, more simply, aria-label on the surrounding command element, which is what most implementations should use.
Mistake: “role="button" alone makes a div behave like a button.” The role only announces what kind of thing the element is to assistive technology. It adds no keyboard focus, no Enter/Space activation, and no accessible name by itself: all three have to be added separately (tabindex, a keydown handler, and a name source), which is exactly why a native <button> is usually less work.
How RedFlag Detects This
Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s aria-command-name rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule selects every element with role button, link, or menuitem and checks whether the accessible name computation resolves to non-empty text through any standard source.
False negative: axe-core confirms a name exists; it can’t judge whether that name is accurate. A command labelled aria-label="Button" or aria-label="Click" passes the automated check even though it’s as unhelpful as having no name at all. False positive: none typical for this check, since resolving to a non-empty accessible name is a binary condition. Manual step: read the announced name for each command and confirm it describes the actual action, not just that a name is technically present.
Manual Testing
- Open the page in Chrome or Firefox with NVDA or JAWS running.
- Tab through every custom button, link, and menu item on the page, especially icon-only toolbar controls.
- Listen to what’s announced immediately after the role: it should be a specific action (“Bold, button”), not the role alone (“button”) and not a generic word like “click” or “icon.”
- On a Mac, repeat the same pass with VoiceOver to confirm the name is consistent across screen readers, since some fallback behaviors differ slightly between them.
- If a command is icon-only, cover the icon and confirm the announced name alone tells you what activating it will do.
Related WCAG Success Criteria
4.1.2 Name, Role, Value: Every interface component must expose a name, role, and current value to assistive technology. A command role with no accessible name has a role but no name, which is exactly the “name” half of this criterion failing.
2.4.4 Link Purpose (In Context): When the command role is link, its purpose must be determinable from its accessible name or surrounding context. An unnamed link fails 2.4.4 at the same time it fails 4.1.2, since there’s no text at all to evaluate for purpose.
Related Issues
ARIA input field has no accessible name covers the same missing-name failure for textbox, combobox, and searchbox roles instead of command roles; the two rules share the exact same fix pattern applied to different widget types.
ARIA toggle field has no accessible name is the equivalent failure for checkbox, radio, and switch roles, which announce a state instead of triggering an action.
Button or link has no accessible name is the native-HTML version of this exact problem: the same failure on a real <button> or <a> element instead of a role-based custom one.
Input button has no accessible name covers <input type="button">, submit, and reset controls, another command-shaped element that needs the same naming fix.
References
- W3C Understanding 4.1.2: Name, Role, Value
- ARIA Authoring Practices: Button Pattern
- MDN: Accessible name
Frequently asked questions
What counts as a command role in ARIA?
ARIA groups button, link, and menuitem together as command roles because all three trigger an action rather than displaying static content. This rule checks any element carrying one of those three roles, regardless of whether the underlying tag is a div, span, or list item.
Does this rule apply to native HTML buttons and links?
It applies to a native button or link with no accessible name too, since both carry an implicit command role, but the more common failure is a div or span with role="button" added by hand and no name attached to it. A native button that only wraps an icon with no text has the identical problem under a different rule name.
Is aria-label the correct fix, or should I use aria-labelledby?
Use aria-labelledby when visible text already exists elsewhere on the page that describes the command, such as a heading the button relates to. Use aria-label when no such text exists, which is the common case for a standalone icon button in a toolbar.
Does adding a title attribute fix a command with no name?
No. The title attribute only produces a mouse-hover tooltip in visual browsers, and screen reader support for reading it as an accessible name is inconsistent. It never reaches touch or keyboard-only users at all, so it cannot substitute for aria-label or visible text.
Why does the accessible name still fail if the icon has alt text?
Alt text belongs to an img element and only feeds the accessible name computation when the image is the sole content of the command and nothing else provides a name. An SVG icon rendered inline with no title element and no aria-label on the surrounding command element contributes nothing to the name at all.