aria-label
Defines a string value that labels the current element. Provides an accessible name when no visible text label is available or when the visible label is insufficient.
Overview
The aria-label attribute provides a text alternative that labels an interactive element. It's especially useful for icon buttons, where there's no visible text, or for disambiguating multiple elements of the same type.
Screen readers will announce the aria-label value instead of (or in addition to) the element's content. This makes it essential for providing context to users who rely on assistive technology.
When to Use aria-label
Use aria-label when there's no visible text label, or when you need to provide additional context. Prefer aria-labelledby if a visible label exists that you can reference.
Live Demo: aria-label in Action
Icon buttons with aria-label:
Screen reader announcement: When focusing these buttons, screen readers will announce the aria-label text (e.g., "Close dialog, button", "Search, button") instead of just "button".
Code Examples
Basic Usage
<!-- Basic aria-label Usage -->
<button aria-label="Close dialog">
<svg><!-- X icon --></svg>
</button>
<button aria-label="Search">
<svg><!-- Magnifying glass icon --></svg>
</button>
<!-- Icon buttons NEED aria-label or aria-labelledby -->Navigation Landmarks
<!-- Navigation Landmarks -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<nav aria-label="Footer navigation">
<ul>
<li><a href="/privacy">Privacy</a></li>
<li><a href="/terms">Terms</a></li>
</ul>
</nav>
<!-- Multiple nav elements need unique labels -->Form Controls
<!-- Form Controls -->
<input
type="search"
aria-label="Search articles"
placeholder="Search..."
/>
<!-- When no visible label exists -->
<button aria-label="Add to favorites">
⭐
</button>
<!-- Complex widgets -->
<div
role="slider"
aria-label="Volume control"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
tabindex="0"
>
<!-- Slider UI -->
</div>aria-label vs aria-labelledby
<!-- aria-label vs aria-labelledby -->
<!-- aria-label: Direct string value -->
<button aria-label="Delete item">
🗑️
</button>
<!-- aria-labelledby: Reference to other element(s) -->
<h2 id="dialog-title">Confirm Delete</h2>
<div role="dialog" aria-labelledby="dialog-title">
<p>Are you sure you want to delete this item?</p>
</div>
<!-- aria-labelledby takes precedence over aria-label -->
<button
aria-label="This will be ignored"
aria-labelledby="visible-text"
>
<span id="visible-text">Click Me</span>
</button>
<!-- Combining multiple labels -->
<button aria-labelledby="action icon-desc">
<span id="action">Delete</span>
<svg id="icon-desc" aria-label="trash can icon">...</svg>
</button>React Examples
// React aria-label Examples
import { useState } from 'react';
// Icon Button with aria-label
function IconButton({ icon, label, onClick }) {
return (
<button
onClick={onClick}
aria-label={label}
className="p-2 hover:bg-gray-100 rounded"
>
{icon}
</button>
);
}
// Search Input
function SearchInput() {
const [query, setQuery] = useState('');
return (
<input
type="search"
aria-label="Search products"
placeholder="Search..."
value={query}
onChange={(e) => setQuery(e.target.value)}
className="px-4 py-2 border rounded"
/>
);
}
// Multiple Navigation Landmarks
function Navigation() {
return (
<>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<nav aria-label="Social media links">
<a href="https://twitter.com" aria-label="Follow us on Twitter">
<TwitterIcon />
</a>
<a href="https://facebook.com" aria-label="Follow us on Facebook">
<FacebookIcon />
</a>
</nav>
</>
);
}
// Slider with aria-label
function VolumeSlider() {
const [volume, setVolume] = useState(50);
return (
<div
role="slider"
aria-label="Volume control"
aria-valuenow={volume}
aria-valuemin={0}
aria-valuemax={100}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'ArrowUp') setVolume(Math.min(100, volume + 10));
if (e.key === 'ArrowDown') setVolume(Math.max(0, volume - 10));
}}
className="w-full h-8 bg-gray-200 rounded cursor-pointer"
>
<div
className="h-full bg-blue-500 rounded"
style={{ width: `${volume}%` }}
/>
</div>
);
}Best Practices
Use aria-label for icon-only buttons to describe their action
Keep aria-label text concise and descriptive
Use aria-label to disambiguate multiple landmarks of the same type
Prefer aria-labelledby when a visible label exists
Ensure aria-label text is translatable if supporting multiple languages
Don't use aria-label on elements that already have visible text labels
Don't use aria-label on non-interactive or non-landmark elements
Don't duplicate visible text in aria-label - it will be announced twice
Don't forget: aria-labelledby overrides aria-label
Common Use Cases
aria-label vs aria-labelledby
aria-label
- • Provides a string value directly
- • Use when no visible label exists
- • Cannot be styled or localized easily
- • Good for icon buttons
aria-labelledby
- • References existing element(s) by ID
- • Use when visible label exists
- • Can reference multiple elements
- • Takes precedence over aria-label
Accessibility Notes
Screen Reader Announcement
Screen readers will announce the aria-label value followed by the element's role. For example, <button aria-label="Close"> will be announced as "Close, button".
Translation Considerations
When using aria-label, remember that the text is hardcoded and may not be automatically translated. For multilingual sites, consider using aria-labelledby with translated visible text, or implement proper internationalization for aria-label values.
Precedence Order
If both aria-labelledby and aria-label are present, aria-labelledby takes precedence. The priority order is: 1) aria-labelledby, 2) aria-label, 3) label element (for inputs), 4) element content.

