aria-label: naming things that have no visible text

An icon-only button is announced as "button". A chart drawn from divs is announced as nothing. aria-label supplies the spoken name in those cases. On an element that already has text, it replaces the text, which is the mistake to avoid.

aria-label is an attribute that gives an element a name for screen readers when nothing visible provides one: a button that is only an icon, a figure whose meaning is in the bars, a link that is only an arrow.

The markup. The highlighted line is the part this term is about.
The markup. The highlighted line is the part this term is about.

The screen reader announces the label instead of "button" or nothing at all.

It has one sharp edge: on an element that already has visible text, the label replaces that text in what is announced, so it belongs only where there is no text to begin with.

This guide covers the four cases where it is right, where it does nothing, where it does harm, and the alternatives that keep the name visible.

<button aria-label="Close">×</button>

Without the label, a screen reader announces "times" or "multiplication sign". With it, "Close, button".

The four cases where aria-label is right

An icon-only control

aria-label gives an element a spoken name when nothing visible does: an icon-only button, a chart drawn from bars. When the element already has text, leave it alone; the label would override what is written.
aria-label gives an element a spoken name when nothing visible does: an icon-only button, a chart drawn from bars. When the element already has text, leave it alone; the label would override what is written.
<button aria-label="Copy the HTML">
  <svg aria-hidden="true" viewBox="0 0 24 24">…</svg>
</button>

The label names the action; aria-hidden on the icon stops its contents being read as a stream of coordinates.

A field with no visible label

<input type="search" aria-label="Search guides" placeholder="Search">

A placeholder is not a label — it vanishes as soon as typing starts and is not reliably announced. If there is no room for a visible label, this is the minimum.

A frame

<iframe src="…" title="Quarterly report"></iframe>

Frames use title rather than aria-label. An unnamed frame is announced as "frame", which tells the listener nothing. See iframe.

Distinguishing two similar regions

<nav aria-label="Main">…</nav>
<nav aria-label="Breadcrumb">…</nav>

Two navigation landmarks are otherwise both announced as "navigation", so a screen reader user cannot tell which is which.

A screenshot of the page ✗ Text is not selectable ✗ Numbers cannot be copied ✗ Charts stop being interactive ✗ Goes stale the moment data changes The live page ✓ Text selects and copies ✓ Tables can be read by tools ✓ Charts still respond to hover ✓ Update the source, link is current
A chart with a labelled figure is read as its values. One without is read as nothing.

Where it does nothing

<!-- ignored: a div has no role to name -->
<div aria-label="Important section">…</div>

<!-- works: the role gives it something to name -->
<div role="region" aria-label="Signups by source">…</div>

aria-label names an element's role. An element with no meaningful role has nothing to name, so the attribute is discarded. Adding it to divs is a common and entirely ineffective habit.

It replaces the visible text

<!-- the reader hears "Submit". The visible word "Save" is never announced. -->
<button aria-label="Submit">Save</button>

This is a real trap. A sighted person is told to click "Save"; a screen reader user is looking for "Submit". Never let the two disagree — if there is visible text, either leave it to speak for itself or make the label start with the same words.

Prefer a visible label

<!-- fine -->
<button aria-label="Delete this row">🗑</button>

<!-- better -->
<button>🗑 Delete</button>

An icon whose meaning is obvious to you is frequently not obvious to a reader. A visible word helps everyone and removes the need for the attribute.

Use aria-label when space genuinely does not permit text — a dense toolbar — and not as the default.

aria-labelledby, when the text is already on the page

<h2 id="sources">Signups by source</h2>
<div role="region" aria-labelledby="sources">…</div>

Points at existing text instead of duplicating it, so the two cannot drift apart. Prefer it whenever a heading already says the thing.

The order to reach for

  1. A real element with real text. <button>Save</button> needs nothing.
  2. A real <label>, for form fields.
  3. aria-labelledby, when the text exists elsewhere on the page.
  4. aria-label, when there is no text anywhere.

Most ARIA in the wild is at step four when step one was available — see semantic HTML. The first rule of ARIA is to not need it.

What it is not for

Three habits that look like accessibility work and are not.

Habit Why it does nothing Instead
aria-label on a <div> No role to name, so it is discarded Give the element a real role, or use a real element
aria-label duplicating visible text Announced twice, or replaces it Leave the text to speak
role="button" on a <button> Already a button Nothing
aria-hidden on something focusable Announced as an unnamed control Remove it from the tab order too

The last row is a real failure: an element hidden from screen readers but still reachable by Tab produces a stop where the listener is told nothing at all. If you hide something, hide it from the tab order as well.

The check that takes a minute

Turn on your operating system's screen reader and Tab through the page. You are listening for one thing: does every stop announce something that identifies it. A stop that says only "button" or "frame" needs a name; a stop that says nothing needs a real element — see semantic HTML.

aria-label, aria-labelledby, and visible labels

aria-label supplies a name as a string. aria-labelledby points at another element whose text is the name, which is better when that text is already on the page, because the two cannot drift apart.

A <label for> on a form field is better than either, because sighted readers see it too. Reach for aria-label only when there is nothing visible to point at.

Testing what is announced

Turn on the screen reader built into the operating system, or use the accessibility tree in the browser's inspector, and move through the page.

Every control should be announced with a name that says what it does; every chart should be announced with its values or a caption. A control announced as "button" with nothing after it is the one that needs a label.

Using aria-label: 4 steps

  1. Find the elements with no visible text. Icon-only buttons, arrow links, close controls, charts drawn from shapes.
  2. Write the purpose, not the picture. "Copy the share link", not "clipboard icon". For a chart, the values: "Signups by source: search 998, direct 527".
  3. Leave elements with visible text alone. An aria-label on a button that says Copy link replaces the words the reader can see with whatever you wrote.
  4. Prefer visible text where it fits. A label everyone can see is better than one only a screen reader hears. Semantic HTML removes most of the need in the first place.

Questions people ask

What does aria-label do?

It supplies the name a screen reader announces for an element. It replaces any text inside, and it is not visible on screen.

When should I use it?

For controls with no text — an icon button, a search field with no label, an iframe, a region that needs distinguishing from a similar one.

When is it ignored?

On elements with no accessible role, such as a plain div or span. Naming a generic container has no effect.

Is visible text better?

Almost always. A visible label helps everyone, including people who can see but are unfamiliar with the icon.

Keep reading