About This Accessibility Rule
A tab is one of the interactive controls in the ARIA tabs pattern, where a tablist holds several tab elements and each tab reveals its matching tabpanel. The accessible name is what a screen reader reads out when focus lands on the tab, so it has to describe the section that the tab opens, such as "Profile", "Security", or "Notifications". When the name is missing, assistive technology falls back to announcing only the role, so the user hears "tab" with nothing to tell one tab from the next.
This shows up most often with icon-only tabs, where the tab holds a single icon and no text, and with tabs built from empty div or span elements styled entirely through CSS. In both cases there is visible meaning on screen, through an icon or a background image, but nothing that assistive technology can read. Keyboard and voice-control users are affected too, since voice commands often target a control by its name.
This rule maps to WCAG Success Criterion 4.1.2 Name, Role, Value (Level A). That criterion requires every user interface component to expose its name, its role, and its current state to assistive technology. A tab already carries its role through role="tab" and its state through aria-selected, but without a name the component is only partly exposed, so the criterion is not met. Level A is the minimum conformance level, and the same criterion applies in WCAG 2.0, 2.1, and 2.2.
How to Fix
Give every element with role="tab" an accessible name using one of these techniques, listed from most to least preferred:
- Put the label text directly inside the tab, so the name is visible to everyone.
- Use
aria-labelledbyto reference theidof an element that already holds the label text. - Use
aria-labelto set the name directly, which suits icon-only tabs that have no visible text. - Use the
titleattribute as a fallback when none of the above fit.
Whichever technique you pick, make the name describe where the tab leads and keep it unique within the tablist, so each tab is easy to tell apart.
Examples
Failing: Icon-only tab with no name
The tab shows an icon but exposes no text, so a screen reader announces only "tab".
<div role="tablist">
<button role="tab" aria-selected="true">
<svg aria-hidden="true" focusable="false"><!-- gear icon --></svg>
</button>
</div>
Failing: Empty aria-label
An aria-label with no value leaves the tab without a name.
<button role="tab" aria-selected="true" aria-label="">
<svg aria-hidden="true" focusable="false"><!-- bell icon --></svg>
</button>
Failing: aria-labelledby pointing nowhere
If the referenced id does not exist, or the element it points to is empty, the tab still has no name.
<button role="tab" aria-selected="true" aria-labelledby="missing-label">
</button>
Passing: Visible text inside the tab
<div role="tablist">
<button role="tab" aria-selected="true">Profile</button>
<button role="tab" aria-selected="false">Security</button>
</div>
A screen reader announces something like "Profile, tab, selected".
Passing: aria-label on an icon-only tab
<button role="tab" aria-selected="true" aria-label="Notifications">
<svg aria-hidden="true" focusable="false"><!-- bell icon --></svg>
</button>
The icon stays decorative with aria-hidden="true", while aria-label supplies the name.
Passing: aria-labelledby referencing visible text
<span id="billing-label">Billing</span>
<button role="tab" aria-selected="false" aria-labelledby="billing-label"></button>
This keeps the visible label and the accessible name in sync, since both come from the same text.
Detect accessibility issues automatically
Rocket Validator scans thousands of pages with Axe Core and the W3C Validator, finding accessibility issues across your entire site.
Learn more: