View contents
ARIA Labels: Providing Accessible Names for Interactive Elements
Introduction
ARIA labels provide accessible names for elements that screen readers announce to users. When native HTML doesn’t provide a clear name—like icon-only buttons or custom widgets—ARIA attributes fill the gap. WCAG 4.1.2 requires that all user interface components have programmatically determinable names, making ARIA labeling essential for accessibility.
Without proper accessible names, screen reader users hear meaningless announcements like “button” or “link” without understanding what the element does. ARIA labels ensure every interactive element communicates its purpose clearly.
Understanding Accessible Names
What Is an Accessible Name?
An accessible name is the text that assistive technologies announce when a user focuses on an element. It can come from various sources:
| Source | Priority | Example |
|---|---|---|
aria-labelledby |
Highest | References another element’s text |
aria-label |
High | Direct label text |
<label> element |
Medium | Form field labels |
| Element content | Lower | Text inside buttons/links |
title attribute |
Lowest | Last resort option |
The Name Calculation
Browsers use a specific algorithm to determine accessible names:
<!-- 1. aria-labelledby wins (highest priority) -->
<button aria-labelledby="btn-label">
<svg>...</svg>
</button>
<span id="btn-label">Search products</span>
<!-- Announced: "Search products, button" -->
<!-- 2. aria-label is next -->
<button aria-label="Search products">
<svg>...</svg>
</button>
<!-- Announced: "Search products, button" -->
<!-- 3. Content is lower priority -->
<button>
<svg aria-hidden="true">...</svg>
Search
</button>
<!-- Announced: "Search, button" -->
ARIA Labeling Attributes
aria-label
Provides a string directly as the accessible name:
<!-- Icon-only button -->
<button aria-label="Close dialog">
<svg aria-hidden="true"><!-- X icon --></svg>
</button>
<!-- Search input -->
<input type="search" aria-label="Search products">
Best for:
- Icon-only buttons
- Inputs without visible labels
- Elements where visual context is clear
Limitations:
- Not translatable by browser translation tools
- Not visible to sighted users
aria-labelledby
References another element’s text as the label:
<!-- Using existing heading -->
<h2 id="section-title">Shopping Cart</h2>
<nav aria-labelledby="section-title">
<!-- Navigation within shopping cart -->
</nav>
<!-- Multiple elements -->
<span id="label">Email</span>
<span id="hint">(required)</span>
<input type="email" aria-labelledby="label hint">
<!-- Announced: "Email (required)" -->
Best for:
- When label text already exists visually
- Combining multiple text sources
- Sections labeled by headings
aria-describedby
Provides supplementary description (not the primary name):
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="pwd-help">
<p id="pwd-help">Must be at least 8 characters with one number</p>
<!-- Announced: "Password, edit text, Must be at least 8 characters..." -->
Difference from labelledby:
aria-labelledby= primary name (announced first)aria-describedby= additional description (announced after)
Common ARIA Label Use Cases
Icon Buttons
<!-- Social media icons -->
<a href="https://twitter.com/company" aria-label="Follow us on Twitter">
<svg aria-hidden="true"><!-- Twitter icon --></svg>
</a>
<button aria-label="Add to favorites">
<svg aria-hidden="true"><!-- Heart icon --></svg>
</button>
Navigation Landmarks
<!-- Multiple nav elements need distinction -->
<nav aria-label="Main navigation">
<!-- Primary navigation -->
</nav>
<nav aria-label="Footer navigation">
<!-- Footer links -->
</nav>
<nav aria-label="Breadcrumb">
<!-- Breadcrumb trail -->
</nav>
Form Regions
<section aria-labelledby="shipping-title">
<h2 id="shipping-title">Shipping Information</h2>
<!-- Shipping form fields -->
</section>
<section aria-labelledby="billing-title">
<h2 id="billing-title">Billing Information</h2>
<!-- Billing form fields -->
</section>
Custom Widgets
<!-- Star rating -->
<div role="slider"
aria-label="Rating"
aria-valuemin="1"
aria-valuemax="5"
aria-valuenow="4">
<!-- Star icons -->
</div>
<!-- Toggle switch -->
<button role="switch"
aria-checked="false"
aria-label="Dark mode">
<!-- Toggle visual -->
</button>
Common Labeling Mistakes
1. Missing Labels
<!-- BAD: No accessible name -->
<button>
<svg><!-- icon --></svg>
</button>
<!-- Announced: "button" - meaningless! -->
<!-- GOOD: Has accessible name -->
<button aria-label="Delete item">
<svg aria-hidden="true"><!-- icon --></svg>
</button>
2. Redundant Labels
<!-- BAD: Redundant information -->
<button aria-label="Submit button">Submit</button>
<!-- Announced: "Submit button, button" - "button" is said twice -->
<!-- GOOD: Let content be the name -->
<button>Submit</button>
<!-- Announced: "Submit, button" -->
3. Labels Not Matching Visible Text
<!-- BAD: Different from visible text -->
<button aria-label="Send message">Submit Form</button>
<!-- Voice control users say "click Submit Form" but it won't work -->
<!-- GOOD: Match or include visible text -->
<button aria-label="Submit Form - sends your message">Submit Form</button>
4. Using aria-label on Non-Interactive Elements
<!-- BAD: aria-label on div (screen readers may ignore) -->
<div aria-label="Important section">Content here</div>
<!-- GOOD: Use on landmarks or interactive elements -->
<section aria-label="Important section">Content here</section>
Testing ARIA Labels
Quick Manual Test
- Open browser DevTools
- Inspect an element
- Check the Accessibility panel
- Look for “Name” property
- Verify it makes sense
Using Screen Readers
| Screen Reader | Command |
|---|---|
| NVDA | Tab to element, listen |
| VoiceOver | VO+Right arrow |
| JAWS | Tab to element |
| Narrator | Tab to element |
Automated Tools
- axe DevTools - Reports missing accessible names
- WAVE - Highlights unlabeled elements
- Lighthouse - Checks for accessible names
- Browser DevTools - Shows computed accessible name
Best Practices Summary
| Do | Don’t |
|---|---|
Use aria-label for icon-only elements |
Put aria-label on non-interactive divs |
Use aria-labelledby when text exists |
Duplicate visible text in aria-label |
| Make labels concise but clear | Write overly long labels |
| Start with action verb for buttons | Include element type in label |
| Test with actual screen readers | Assume visual clarity = accessibility |
When to Use Each Attribute
| Situation | Use |
|---|---|
| Icon-only button | aria-label |
| Existing visual label nearby | aria-labelledby |
| Form field without visible label | aria-label |
| Additional help text | aria-describedby |
| Multiple nav landmarks | aria-label on each |
| Section with heading | aria-labelledby to heading |
Related Articles
- ARIA Labels Implementation Guide - Detailed patterns
- Form Labels Guide - Native labeling
- Accessible Components Hub - Full guide
References
- W3C - WCAG 2.2 SC 4.1.2 Name, Role, Value
- W3C - Accessible Name Computation
- WebAIM - ARIA
- MDN - Using aria-label