EduFlow

Section 4 · Visual Design and Content

Accessible Names and Descriptions

18 min3 min readCode playground

Lesson at a glance

Predict the accessible name and description a browser computes for any control, and give icon buttons and repeated buttons names that are unique and match their visible label.

  1. 1How the browser computes a name
  2. 2Icon-only buttons
  3. 3Repeated buttons and Label in Name
  4. 4Descriptions

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Ticketly’s event page has three buttons that all say “Book now”, a close button that shows “×”, a search button containing only an SVG magnifying glass, and a newsletter button whose name a developer set to “newsletter-cta” for analytics. In a screen reader’s list of buttons, the page reads: “Book now, Book now, Book now, times, button, newsletter-cta”. Every one of those is a naming problem, and you fix all of them by understanding one algorithm.

How the browser computes a name

The W3C’s Accessible Name and Description Computation spec defines exactly how a browser picks a name. Simplified, it tries these sources in order and takes the first one that produces text:

  1. aria-labelledby: the text of the referenced elements, joined with spaces, in the order of the ids.
  2. aria-label: the attribute’s string.
  3. Native labelling: a <label> for form fields, alt for images, <legend> for a fieldset, <caption> for a table, <title> for an SVG.
  4. Content, for roles that allow it: buttons, links, headings, tabs, table cells, menu items and options. Text inside, plus the alt of images inside, minus anything with aria-hidden="true".
  5. title (and placeholder for inputs) as a last resort.
A ladder of five steps from highest to lowest priority: aria-labelledby, aria-label, native label such as label, alt or legend, content for buttons links and headings, and finally title or placeholder. The first step that yields text becomes the name. 1 aria-labelledby 2 aria-label 3 label, alt, legend, caption 4 content (button, link, heading) 5 title, placeholder lower priority
Where a name comes from, highest priority first

Two consequences matter every day. First, ARIA naming overrides visible text: once you add aria-label, the button’s own content is ignored. Second, names don’t merge: if aria-labelledby exists, the element’s aria-label is skipped. The one twist: if aria-labelledby lists the element’s own id, that self-reference resolves to its aria-label when it has one, not to its content. You can check any result in the browser: Chrome’s Accessibility pane and Firefox’s Accessibility Inspector both show the computed name.

Icon-only buttons

A button with only an icon has no text content, so it has no name, unless you give it one. Three options, in order of preference:

ticketly/header.html
<!-- 1. Visible text next to the icon: best for everyone -->
<button type="button" class="search">
  <svg aria-hidden="true" viewBox="0 0 24 24">…</svg>
  Search
</button>

<!-- 2. Visually hidden text: the design stays icon-only -->
<button type="button" class="close">
  <span aria-hidden="true">×</span>
  <span class="visually-hidden">Close banner</span>
</button>

<!-- 3. aria-label: fine, but invisible to translation tools that skip attributes -->
<button type="button" class="close" aria-label="Close banner">
  <span aria-hidden="true">×</span>
</button>

Notice the aria-hidden="true" on the “×”. Without it, option 2’s name would be “× Close banner”, read by some screen readers as “times Close banner”.

Repeated buttons and Label in Name

Three “Book now” buttons are fine visually, because each sits in its card. In a list of buttons they are indistinguishable. You want names like “Book now, Friday pass” without changing the visible design. aria-labelledby can reference the button itself plus the card heading:

HTML
<article>
  <h3 id="fri-title">Friday pass</h3>
  <button type="button" id="fri-book" aria-labelledby="fri-book fri-title">Book now</button>
</article>

The name becomes “Book now Friday pass”. The visible words come first, which matters for 2.5.3 Label in Name (A): the accessible name must contain the visible label, and best practice is to start with it. Dina, who uses voice control, says “click Book now”; her software finds the three matches and numbers them for her to choose. If the name had been “Reserve Friday” she would have no way to click it by saying what she sees. That is exactly what was wrong with the “newsletter-cta” button: the visible word “Subscribe” isn’t in the name at all. Delete the aria-label and the content provides the right name again.

Descriptions

A description is secondary information, announced after the name and role, usually after a short pause. aria-describedby works like aria-labelledby but feeds the description instead:

HTML
<label for="promo">Promo code</label>
<input id="promo" aria-describedby="promo-hint">
<p id="promo-hint">Codes are 8 letters, for example HARBOUR8.</p>

NVDA reads “Promo code, edit text, Codes are 8 letters, for example HARBOUR8.” Use descriptions for hints, formats and error messages, as you did in the forms lesson. Keep the name short and the description optional: users can skip it, but they can’t skip a name.

Every control on Ticketly now has a name a person could say out loud. The last lesson of this section looks at the words themselves: plain language, and the language attributes that make Ticketly’s Arabic content sound right.

Key takeaways

  • Browsers compute a control’s name in a fixed order: aria-labelledby, then aria-label, then native labelling (label, alt, legend, caption), then the element’s content, then title.
  • aria-labelledby and aria-label override everything else, including visible text, so use them carefully.
  • A visible label must appear in the accessible name (2.5.3 Label in Name), ideally at the start, so voice control users can say what they see.
  • aria-describedby adds secondary information, read after the name and role; it is for hints and errors, not for the name itself.

Further reading

Check your understanding

3 questions

Question 1 of 3

What is the accessible name of this button?

HTML
<h3 id="fri">Friday pass</h3>
<button id="b1" aria-label="Buy" aria-labelledby="b1 fri">Book now</button>
Question 2 of 3

A voice control user says “click Get tickets”. Nothing happens. Why?

HTML
<a href="/tickets" aria-label="Purchase festival passes">Get tickets</a>
Question 3 of 3

Which element’s accessible name comes from its content?

Practice

Code playground

Name every button on the event page

A screen reader lists Ticketly’s buttons as “times, button, Book now, Book now, Book now, newsletter-cta”. Fix the names without changing what sighted users see:

  1. The .close “×” button needs a name containing “Close” (or “Dismiss”); the “×” itself shouldn’t be read.
  2. The icon-only .search button needs the name “Search”.
  3. Each .book button needs a unique name that starts with “Book now” and includes its pass (Friday, Saturday or Weekend).
  4. The .subscribe button’s name must contain its visible word “Subscribe”.
<div class="banner">
  <p>Early-bird prices end Friday.</p>
  <button type="button" class="close">×</button>
</div>

<header class="bar">
  <strong>Ticketly</strong>
  <button type="button" class="search"><svg viewBox="0 0 24 24" width="18" height="18"><circle cx="10" cy="10" r="6" fill="none" stroke="currentColor" stroke-width="2"/><path d="M15 15 L21 21" stroke="currentColor" stroke-width="2"/></svg></button>
</header>

<div class="cards">
  <article class="card">
    <h3>Friday pass</h3>
    <button type="button" class="book">Book now</button>
  </article>
  <article class="card">
    <h3>Saturday pass</h3>
    <button type="button" class="book">Book now</button>
  </article>
  <article class="card">
    <h3>Weekend pass</h3>
    <button type="button" class="book">Book now</button>
  </article>
</div>

<footer>
  <label for="news-email">Email</label>
  <input id="news-email" type="email" autocomplete="email">
  <button type="button" class="subscribe" aria-label="newsletter-cta">Subscribe</button>
</footer>Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

Preview

Console

(no output)

Checks

  • The close button is named Close (or Dismiss) and the × isn’t read
  • The search button is named Search
  • The three Book now buttons have unique names that include their pass
  • Every name contains its visible text, and Book now names start with it
  • The Subscribe button’s name contains “Subscribe”