Accessible Names and Descriptions
Accessible Names and Descriptions
Every interactive element needs an accessible name, the text that screen readers announce to identify the element. Getting accessible names right is fundamental to web accessibility. This guide explains how accessible names are calculated and how to provide them correctly.
What Is an Accessible Name?
The accessible name is the text that identifies an interactive element to assistive technology users. It answers: "What is this thing?"
<!-- Accessible name: "Submit form" -->
<button>Submit form</button>
<!-- Accessible name: "Username" -->
<label>
Username
<input type="text">
</label>
<!-- Accessible name: "About Us" -->
<a href="/about">About Us</a>The Accessible Name Calculation
Browsers follow a specific algorithm to determine accessible names. In priority order:
1. aria-labelledby
References another element's text:
<h2 id="section-title">Account Settings</h2>
<form aria-labelledby="section-title">
<!-- Accessible name: "Account Settings" -->
</form>
<!-- Multiple IDs -->
<span id="prefix">New</span>
<span id="main">Message</span>
<button aria-labelledby="prefix main">Send</button>
<!-- Accessible name: "New Message" -->2. aria-label
Direct label on the element:
<button aria-label="Close dialog">X</button>
<!-- Accessible name: "Close dialog" -->
<nav aria-label="Main navigation">...</nav>
<!-- Accessible name: "Main navigation" -->3. Native Labeling
HTML's built-in labeling mechanisms:
<!-- label element -->
<label for="email">Email address</label>
<input id="email" type="email">
<!-- Accessible name: "Email address" -->
<!-- Wrapped label -->
<label>
Password
<input type="password">
</label>
<!-- Accessible name: "Password" -->
<!-- Alt text for images -->
<img src="logo.png" alt="Company Logo">
<!-- Accessible name: "Company Logo" -->
<!-- legend for fieldset -->
<fieldset>
<legend>Shipping Address</legend>
<!-- Accessible name: "Shipping Address" -->
</fieldset>4. Text Content
The visible text inside the element:
<button>Save Changes</button>
<!-- Accessible name: "Save Changes" -->
<a href="/help">Get Help</a>
<!-- Accessible name: "Get Help" -->5. title Attribute (Fallback)
Used as last resort if nothing else available:
<button title="Submit form"><svg>...</svg></button>
<!-- Accessible name: "Submit form" (if no other source) -->Accessible Descriptions
Descriptions provide additional context beyond the name. They answer: "What else should I know?"
<label for="password">Password</label>
<input
id="password"
type="password"
aria-describedby="password-hint"
>
<p id="password-hint">
Must be at least 8 characters with one uppercase letter
</p>
<!-- Name: "Password" -->
<!-- Description: "Must be at least 8..." -->Common Patterns
Icon Buttons
<!-- Method 1: aria-label -->
<button aria-label="Delete item">
<svg aria-hidden="true">...</svg>
</button>
<!-- Method 2: Visually hidden text -->
<button>
<svg aria-hidden="true">...</svg>
<span class="sr-only">Delete item</span>
</button>Icon + Text Buttons
<!-- Icon is decorative -->
<button>
<svg aria-hidden="true">...</svg>
Download PDF
</button>
<!-- Name: "Download PDF" -->Images
<!-- Informative image -->
<img src="chart.png" alt="Sales grew 25% in Q3">
<!-- Decorative image -->
<img src="decorative.png" alt="">
<!-- Image link -->
<a href="/profile">
<img src="avatar.jpg" alt="John Doe's profile">
</a>Form Fields
<!-- Explicit label -->
<label for="name">Full name</label>
<input id="name" type="text">
<!-- With description -->
<label for="dob">Date of birth</label>
<input
id="dob"
type="date"
aria-describedby="dob-format"
>
<p id="dob-format">Format: MM/DD/YYYY</p>
<!-- Required field -->
<label for="email">
Email address <span aria-hidden="true">*</span>
</label>
<input
id="email"
type="email"
aria-required="true"
>Multiple Labels
<table>
<tr>
<td></td>
<th id="price">Price</th>
<th id="qty">Quantity</th>
</tr>
<tr>
<th id="apples">Apples</th>
<td>
<input aria-labelledby="apples price">
</td>
<td>
<input aria-labelledby="apples qty">
</td>
</tr>
</table>
<!-- First input name: "Apples Price" -->
<!-- Second input name: "Apples Quantity" -->React Patterns
// Icon button component
function IconButton({ icon: Icon, label, onClick }) {
return (
<button onClick={onClick} aria-label={label}>
<Icon aria-hidden="true" />
</button>
);
}
// Input with error description
function TextField({ label, error, ...props }) {
const id = useId();
const errorId = `${id}-error`;
return (
<div>
<label htmlFor={id}>{label}</label>
<input
id={id}
aria-invalid={!!error}
aria-describedby={error ? errorId : undefined}
{...props}
/>
{error && <p id={errorId} className="error">{error}</p>}
</div>
);
}Testing Accessible Names
Browser DevTools
- Open Elements panel
- Select an element
- View Accessibility tab
- Check "Computed Properties" > "Name"
Automated Testing
// Using Testing Library
expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument();
// Using axe-core
const results = await axe(container);
const nameIssues = results.violations.filter(
v => v.id === 'button-name' || v.id === 'input-name'
);Common Mistakes
Mistake 1: Empty or Missing Names
<!-- Bad: No accessible name -->
<button><svg>...</svg></button>
<input type="text" placeholder="Search">
<!-- Good -->
<button aria-label="Search"><svg>...</svg></button>
<label>
<span class="sr-only">Search</span>
<input type="text" placeholder="Enter search term">
</label>Mistake 2: Redundant Names
<!-- Bad: "Search button button" -->
<button aria-label="Search button">Search</button>
<!-- Good: Just the action -->
<button>Search</button>Mistake 3: Non-Descriptive Names
<!-- Bad -->
<button aria-label="Click here">Submit</button>
<!-- Good -->
<button>Submit Application</button>Accessible Name Checklist
- All interactive elements have accessible names
- Names are concise but descriptive
- aria-label used for icon-only elements
- Form fields properly labeled
- Decorative images have empty alt
- No redundant labeling
- Tested with screen reader
Was this article helpful?