aria-label, aria-labelledby, and aria-describedby give developers fine-grained control over accessible names and descriptions when native labelling markup isn't enough on its own.
1aria-label For Standalone Naming
aria-label sets the accessible name directly as a string on the element it's applied to, without needing any visible text to reference. It's most valuable on icon-only controls — a magnifying-glass search button, a hamburger menu toggle, a trash-can delete icon — where adding visible text would clutter the design but omitting a name entirely leaves screen reader users with nothing.
Because aria-label overrides any visible text content in the accessible name computation, using it on an element that already has clear visible text is a common source of the exact 'text mismatch' bug covered in the previous lesson — don't add it redundantly.
2aria-labelledby For Reusing Existing Text
When a suitable label already exists visibly on the page — most often a heading — aria-labelledby lets you reference it by id instead of duplicating the text into an aria-label. This keeps the accessible name automatically synchronized: if the heading text changes, the accessible name changes with it, with zero risk of drift.
aria-labelledby also uniquely supports referencing multiple ids, space-separated, letting you compose a name from several text fragments — commonly used to combine a category label with an item name in data tables or card grids.
3aria-describedby For Hints And Errors
aria-describedby is announced after the accessible name and role, as supplementary description — never as a replacement for the name itself. It's the standard mechanism for connecting format hints ('Minimum 8 characters'), helper text, and, critically, live validation error messages to the field they describe.
A frequent real-world pattern combines aria-describedby with aria-invalid: when a field fails validation, aria-invalid="true" is set and aria-describedby points at the newly-rendered error message, so a screen reader user hears both that the field is invalid and exactly why in a single focus event.
4Step-by-Step Breakdown
Naming What Has No Visible Text. Not every control has visible text to derive a name from — icon-only buttons, unlabeled inputs, and complex widgets often need an explicit label. ARIA gives you three related but distinct tools: aria-label, aria-labelledby, and aria-describedby, each with a different job.
aria-label: An Inline Text Alternative. aria-label supplies an accessible name directly as a string, with no visible on-screen text required. It's the right tool exactly when there is no existing visible label to reference — most commonly icon-only buttons.
aria-label Use Case. An icon-only trash button has no visible text. Which attribute directly supplies its accessible name?
- →The title attribute exclusively
- →aria-label
- →alt, since it works on any element
aria-labelledby: Point At Existing Text. aria-labelledby references the id of another element and uses its text content as the accessible name — useful when a suitable label already exists elsewhere on the page, like a heading that should also name a related region.
aria-labelledby vs aria-label. When is aria-labelledby preferable to aria-label?
- →Always — it's a strict upgrade over aria-label
- →When suitable, already-visible text exists elsewhere to reuse
- →Never; aria-labelledby is deprecated
aria-describedby: Supplementary, Not Primary. aria-describedby adds a secondary description announced after the accessible name, typically used for hints, format requirements, or error messages — it never replaces the name itself, only supplements it.
aria-describedby Purpose. A password field has a visible hint 'Minimum 8 characters' below it. What's the correct way to connect it for screen reader users?
- →aria-describedby, pointing at the hint's id
- →aria-labelledby, replacing the primary label
- →Rely on the placeholder attribute alone
Labelling Toolkit Complete. You can now choose correctly between aria-label for standalone naming, aria-labelledby for reusing existing text, and aria-describedby for supplementary hints — the toolkit behind nearly every properly-labeled custom control.
Label An Icon-Only Button. A button with only an icon needs an aria-label so screen readers can announce its purpose.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1aria-label Overrides Visible Text — Use It Deliberately
Because aria-label wins in the accessible name computation, applying it to an element that already has clear visible text risks silently hiding that text from screen reader users.
2aria-describedby Composes With Validation States For Complete Error Messaging
Pairing aria-invalid="true" with aria-describedby pointing at an error message delivers the field's invalid state and the reason in a single, efficient announcement.
SEO Implications
- 1
aria-label Text Is Not Indexed The Way Visible Text Is
Search engines weight visible, crawlable text far more heavily than aria-label strings, so aria-label should never be used as a substitute for real visible copy intended for SEO.
- 2
Reused, Synchronized Labels Via aria-labelledby Reduce Content Drift Risk
Because aria-labelledby always reflects current visible text, it avoids the SEO-irrelevant but UX-relevant risk of stale, duplicated label strings appearing out of sync with the page.
Best Practices
Prefer aria-labelledby Over aria-label When Visible Text Already Exists
It keeps the accessible name automatically synchronized with visible content, eliminating an entire category of label-drift bugs that plague duplicated aria-label strings.
Always Pair aria-invalid With aria-describedby On Validation Errors
Announcing only 'invalid' without the reason forces users to hunt for the error manually; combining both delivers a complete, actionable message in one announcement.
Frequent Bugs
A search button visibly says 'Search' but the screen reader announces just 'Go'.
A leftover aria-label="Go" is overriding the current visible text. Remove the aria-label or update it to match.
A form shows a red error message visually, but screen reader users tab past the field with no indication anything is wrong.
The error message isn't connected via aria-describedby, and aria-invalid isn't set. Wire both attributes to the rendered error element.
Real-World Examples
Composed Table Cell Label
A data table where each cell's accessible name combines its row and column headers using aria-labelledby.
<th id="col-status">Status</th>
<tr>
<th id="row-1">Invoice #1042</th>
<td aria-labelledby="row-1 col-status">Paid</td>
</tr>