Give every control an accessible name and use ARIA only when HTML cannot do the job.
Why this matters
Every control needs an accessible name: the text a screen reader announces and the words a voice control user says ("click Search"). WCAG 4.1.2 Name, Role, Value and 1.3.1 Info and Relationships (both Level A) require it, and missing names are among the most common failures automated tools find. ARIA (Accessible Rich Internet Applications) is the toolkit for filling gaps HTML cannot, but used carelessly it makes pages worse.
Where accessible names come from
The browser computes a name for each element in a fixed priority order (simplified):
aria-labelledby(points at other elements' ids; their text becomes the name)aria-label(a string)- The native label:
<label>for inputs,altfor images,<caption>for tables,<legend>for fieldsets - The element's text content (for buttons, links and headings)
title(a weak last resort; avoid relying on it)
You can see the result in Chrome or Firefox DevTools: Inspect an element and open the Accessibility pane.
Labels for form fields
Always start with a visible <label>:
<label for="email">Email address</label>
<input id="email" name="email" type="email" autocomplete="email" required aria-describedby="email-hint">
<p id="email-hint">We only use this to send your receipt.</p>
for/idlinks the label, so clicking the label focuses the input and the name is "Email address".- Placeholders are not labels. They disappear when you type, are often low contrast, and are not reliably announced.
aria-describedbyadds a description, announced after the name: perfect for hints and error messages.requiredis native and exposed to assistive technology; you do not needaria-requiredas well.autocompletehelps everyone and supports WCAG 1.3.5 Identify Input Purpose (AA).
Group related controls such as radio buttons with <fieldset> and <legend>.
Icon-only buttons
A magnifying-glass button with only an SVG has no name; a screen reader says "button". Two good fixes:
<!-- Option 1: aria-label, and hide the decorative icon -->
<button type="submit" aria-label="Search">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
<!-- Option 2: visually hidden text (also translated by browser translation tools) -->
<button type="submit">
<svg aria-hidden="true" focusable="false">...</svg>
<span class="visually-hidden">Search</span>
</button>
If a control has visible text, the accessible name should contain that text (WCAG 2.5.3 Label in Name), so voice users can say what they see. Do not put aria-label="Submit form" on a button that reads "Send".
Images
- Informative image:
altdescribes what it conveys (alt="Acme Tools logo", notalt="image"). - Decorative image:
alt=""so screen readers skip it. Leavingaltout entirely makes some screen readers read the file name. - Image inside a link: the alt describes the link's destination.
The W3C's alt decision tree is worth bookmarking.
The rules of ARIA
The W3C's Using ARIA note sets out five rules. The first is the one people quote:
- If a native HTML element has the semantics and behaviour you need, use it instead of re-purposing an element and adding ARIA.
- Do not change native semantics unless you really have to (no
<h2 role="tab">; wrap or restructure instead). - All interactive ARIA controls must be keyboard operable.
- Do not use
role="presentation"oraria-hidden="true"on a focusable element. - All interactive elements must have an accessible name.
ARIA only changes what assistive technology is told. It adds no behaviour. <div role="button"> announces "button" but still cannot be focused or activated with Enter and Space unless you add tabindex="0" and key handlers yourself. A real <button> does all of that already. This is why audits regularly find that pages with ARIA have more errors than pages without it.
ARIA you will actually use
| Attribute | Use it for |
|---|---|
aria-label, aria-labelledby | Naming controls with no visible label, or landmarks (<nav aria-label="Breadcrumb">) |
aria-describedby | Hints and error messages |
aria-expanded, aria-controls | Disclosures, menus, accordions |
aria-current="page" | The current link in navigation |
aria-hidden="true" | Hiding decorative icons from assistive technology |
aria-live="polite", role="status" | Announcing "Saved" or "3 results" without moving focus (4.1.3) |
aria-invalid="true" | Marking a field with an error |
For complex widgets (tabs, comboboxes, menus, tree views), follow the ARIA Authoring Practices Guide and test with real screen readers; the patterns include required keyboard behaviour, not just attributes.
Worked example: fixing a newsletter form
Before: <input placeholder="Email">, a hint in a <small> floating nearby, a <div role="button" onclick="subscribe()">Subscribe</div>, and a decorative swoosh image with no alt.
After: a visible <label for="email">, aria-describedby linking the hint, a real <button type="button">Subscribe</button> (the role attribute removed), and alt="" on the swoosh. Four changes, every one of them plain HTML except aria-describedby.
Common mistakes
- Placeholder text as the only label.
aria-labelon a<div>or<span>with no role: many screen readers ignore it there.- Redundant ARIA:
<button role="button">,<nav role="navigation">. Harmless at best, noise at worst. aria-hidden="true"on something that can still receive focus.- Names that do not match the visible text.
Quick recap
- Every control needs an accessible name; check it in the DevTools Accessibility pane.
- Prefer visible
<label>s, button text andalt; usearia-label/aria-labelledbywhen there is no visible text. aria-describedbyfor hints and errors.- First rule of ARIA: use native HTML. ARIA changes announcements, not behaviour.
Try it
Open the Do tab and fix the labels and ARIA in a newsletter form.