An accessible name is the string that assistive technology announces when a control receives focus. Every interactive element — every <input>, <select>, <textarea>, <button>, and link — MUST have one. The browser computes it from a strict priority chain: aria-labelledby > aria-label > associated <label> > placeholder > title. Whichever entry comes first wins, and everything below it is ignored.
aria-labelledby > aria-label > <label> > placeholder > title.<label>. Only reach for ARIA when a visible label is genuinely impossible (icon-only inputs, search bars, compact toolbars).Think of the accessible name as the spoken caption on a button you cannot see. If the caption is missing, blank, or wrong, the user is pressing a mystery button — and the priority chain decides which caption wins.
<label>For most text inputs, a properly associated <label> is enough. But four common UI patterns force you outside that comfort zone — and that is where accessible-name bugs cluster.
These patterns are also the highest-traffic interactions on most sites — search, login, and checkout — so a single missing accessible name affects every visit.
When a control gets focus, the browser walks the priority chain and uses the first non-empty value it finds. Everything lower in the chain is discarded.
aria-labelledby — points at one or more element IDs whose text content is concatenated to form the name. Highest priority. Strongest pattern when a name needs to combine text from multiple places.aria-label — a string set directly on the element. Wins over a real <label>, which is why misuse breaks voice-control users.<label> — explicit (for/id) or implicit (wrapping). The default and best pattern for visible labels.placeholder — used as a fallback by some screen readers when nothing above is present. Never rely on this; it disappears on focus and fails contrast.title — last resort, behavior varies between browsers and screen readers. Avoid.<!-- Search bar: aria-label provides the name when no visible label fits -->
<input type="search" aria-label="Search articles" placeholder="Search">
<!-- Phone field with separate country-code dropdown,
combined into one accessible name with aria-labelledby -->
<span id="phone-label">Phone number</span>
<span id="cc-label">Country code</span>
<select id="cc" aria-labelledby="phone-label cc-label">
<option value="+1">+1</option>
<option value="+44">+44</option>
</select>
<input type="tel" aria-labelledby="phone-label" name="phone">
<!-- Icon-only delete button: visually-hidden text gives the name -->
<button type="button">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<use href="#icon-trash" />
</svg>
<span class="visually-hidden">Delete item</span>
</button><label>, broken aria-labelledby reference, empty aria-label="").aria-input-field-name, label, and aria-valid-attr-value rules cover the most common accessible-name failures.<label>; Reach for ARIA Only When You MustA correctly associated <label> gives you the accessible name plus expanded click targets, autofill, and CSS targeting. aria-label gives you only the name. Use ARIA when a visible label genuinely cannot fit, not as a default.
aria-label for Icon-Only and Search InputsWhen an input has no adjacent visible text — a search field with only a magnifying-glass icon, a close button on a modal — set aria-label to the action the control performs.
<input type="search" aria-label="Search the documentation"
placeholder="Search">aria-labelledby to Compose Names from Existing TextWhen the most accurate name is already on the page (a heading, a fieldset legend, a table column header), point at it. This avoids duplicating text and keeps the name in sync if the heading changes.
<h2 id="billing-heading">Billing address</h2>
<label id="street-label">Street</label>
<input type="text"
aria-labelledby="billing-heading street-label"
name="billingStreet">
<!-- Announced as: "Billing address Street, edit text" -->When an icon sits inside a labeled control, mark the icon with aria-hidden="true" so its alt text or SVG title does not pollute the accessible name.
<button type="submit" aria-label="Search">
<svg aria-hidden="true" focusable="false" width="20" height="20">
<use href="#icon-search" />
</svg>
</button>WCAG 2.2 SC 2.5.3 Label in Name (Level A) requires the accessible name to contain the visible label text in the same order. If the visible label says "Subscribe" but aria-labelsays "Sign up", voice-control users saying "click subscribe" cannot trigger the control.
aria-label=""An empty aria-label is worse than no aria-label — it overrides the real <label> and replaces the accessible name with an empty string. The control becomes anonymous to assistive technology even though a perfectly good <label> sits next to it.
aria-labelledby ID Existsaria-labelledby="nonexistent-id" fails silently — the accessible name becomes empty. Write tests that assert every ID referenced by aria-labelledby resolves to an element on the page, or rely on a linter / accessibility scanner to catch it.
aria-describedby with the Name, Don't Replace ItHint text, format examples, and validation messages belong in aria-describedby, not aria-label. Description is announced after the name — keeping the name short and the helper text discoverable.
<label for="pwd">Password</label>
<input type="password" id="pwd" aria-describedby="pwd-help">
<p id="pwd-help">At least 12 characters with a number and symbol.</p>aria-label Overrides a Better Visible LabelWhat's happening: A developer adds aria-label="Email" to an input that already has a visible <label> reading "Work email address". Because aria-label wins the priority chain, screen readers now announce the less informative name and voice-control users cannot say "click work email".
Fix: Remove the aria-label. The associated <label> already provides the accessible name, expanded click target, and SC 2.5.3 Label-in-Name compliance.
aria-labelledby Points at a Missing or Renamed IDWhat's happening: The form references aria-labelledby="billing-heading", but the heading was renamed to id="billing-title" during a refactor. The accessible name silently becomes empty.
Fix: Add an automated check (axe rule aria-valid-attr-value, or a Greadme deep scan) and a unit test asserting every referenced ID resolves. In templates, derive both IDs from a single constant.
What's happening: A search input has only placeholder="Search". Some screen readers fall back to the placeholder; others announce nothing. The behaviour is inconsistent across NVDA, JAWS, and VoiceOver.
Fix: Add either a visually-hidden <label> or an aria-label="Search". Keep the placeholder as a hint, not the name.
aria-label="" Hides the Real LabelWhat's happening: A component receives aria-label={props.label} as a prop, but the parent forgot to pass label. The result is aria-label="", which overrides the real <label> with an empty string.
Fix: Render aria-label conditionally — only set it when the prop is a non-empty string. aria-label={props.label || undefined} is the safe default in React.
<label> vs aria-label vs aria-labelledbyThe three primary naming mechanisms differ in priority, capability, and side effects. Pick the one that matches the visible UI.
| Mechanism | <label> | aria-label | aria-labelledby |
|---|---|---|---|
| Priority in name chain | Third | Second | First (highest) |
| Visible to all users? | Yes | No (assistive tech only) | Yes (text already on the page) |
| Expands click target? | Yes | No | No |
| Combines multiple text sources? | No | No | Yes (space-separated ID list) |
| Best for | Standard text inputs, selects, textareas | Icon-only and search inputs | Compound fields, table-style forms |
| Common failure mode | Mismatched for/id | Empty string overrides real label | Reference points at non-existent ID |
A label is one specific HTML element (<label>). The accessible name is the broader concept — the final string the browser exposes to assistive technology after walking the priority chain. A <label> is the most common source of an accessible name, but aria-label, aria-labelledby, placeholder, and title can all contribute.
aria-label or <label>?aria-label wins. If a control has both a real <label> and an aria-label, screen readers announce the aria-label value and ignore the visible label. This is why empty or wrong aria-label attributes are a common bug: they silently override a perfectly good <label>.
aria-label on a div styled as an input?Only if the div has the right role and keyboard behaviour. aria-label on a plain <div> does nothing — the element has no interactive role. If you must build a custom input, set role="textbox" (or whichever role applies), make it focusable with tabindex="0", and handle keyboard events yourself. Native <input> remains far simpler and more robust.
Use aria-label="Search" (or a more specific phrase like "Search articles") on the <input type="search">, or include a visually-hidden <label>. Both work. The <label> approach is preferred because it survives later design changes that might bring back a visible label, and it expands the click target.
Indirectly, yes. AI search engines (ChatGPT search, Perplexity, Google AI Overviews) and Google all use accessibility scores as one quality signal. Forms with broken accessible names fail automated audits, lower the page's overall accessibility score surfaced in Google Search Console, and reduce the page's odds of being cited. AI Overviews also preferentially surfaces pages whose forms are machine-parseable — accessible-name bugs hurt that parseability.
SC 4.1.2 Name, Role, Value (Level A) requires that every interactive UI component have a programmatically determinable name and role. SC 2.5.3 Label in Name (Level A, WCAG 2.1+) additionally requires that when a control has visible text, the accessible name must include that text in the same order. SC 3.3.2 Labels or Instructions (Level A) covers the user-facing requirement to label form fields.
title as a fallback name?No. The title attribute appears in the name chain only as a last resort, and behaviour varies between browsers and screen readers. It also produces a tooltip that does not appear on touch devices and is invisible to keyboard users. Use a real <label>, a visually-hidden label, or aria-label instead.
The accessible name is the single most important accessibility property of any input. Browsers compute it deterministically from a five-step priority chain — aria-labelledby, aria-label, <label>, placeholder, title — and the first non-empty entry wins. That determinism is what makes accessible-name bugs both common and easy to fix once you know where to look.
Default to a real <label> for every text input. Reach for aria-label on icon-only and search inputs where no visible text fits, and use aria-labelledby when the perfect name already exists somewhere else on the page. Run a Greadme deep scan to find every input on your site whose accessible name is empty, broken, or overridden — then fix them in order of traffic.