Screen Readers

Accessible Names and Descriptions

14 min read

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?"

html
<!-- 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:

html
<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:

html
<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:

html
<!-- 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:

html
<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:

html
<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?"

html
<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

html
<!-- 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

html
<!-- Icon is decorative -->
<button>
  <svg aria-hidden="true">...</svg>
  Download PDF
</button>
<!-- Name: "Download PDF" -->

Images

html
<!-- 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

html
<!-- 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

html
<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

jsx
// 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

  1. Open Elements panel
  2. Select an element
  3. View Accessibility tab
  4. Check "Computed Properties" > "Name"

Automated Testing

javascript
// 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

html
<!-- 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

html
<!-- Bad: "Search button button" -->
<button aria-label="Search button">Search</button>

<!-- Good: Just the action -->
<button>Search</button>

Mistake 3: Non-Descriptive Names

html
<!-- 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?