What is aria-labelledby?
The aria-labelledby attribute is part of WAI-ARIA, the Web Accessibility Initiative's Accessible Rich Internet Applications spec. It gives an interactive element its accessible name by pointing to the ID attribute of one or more other elements already on the page, instead of writing new label text. Assistive technologies read the referenced elements' text content aloud in place of the element's own content, which means aria-labelledby is the standard way to reuse an existing heading, caption, or piece of visible text as an accessible name.
At a glance
Why is aria-labelledby important when it comes to accessibility?
Interactive elements and form inputs need an accessible name so assistive technologies can tell users what they are – a requirement the Web Content Accessibility Guidelines (WCAG) treats as fundamental. Landmark regions benefit from one too, especially when a page has more than one of the same type.
Sighted users often work this out from context: a heading sitting above a form section, or a paragraph positioned next to a slider, for example. Screen reader users don't get that visual context. They rely on the accessibility tree: the structured representation of the page that browsers build for assistive technologies to read.
Missing accessible names show up again and again among common website accessibility issues found during QA.
The aria-labelledby attribute lets you carry that visual relationship into the accessibility tree without duplicating any text. If a <section> already sits under a heading that describes it, or a custom slider already has a nearby label, aria-labelledby references visible text and turns it into that element's accessible name.
The attribute is most useful when it comes to custom widgets, dialogs, and form controls built from elements that have no native labeling element of their own, such as <div> or <span> components with an ARIA role attached.
Native HTML elements like <label>, <legend>, and <caption> cover plenty of cases, but aria-labelledby fills the gaps that custom user interface patterns leave behind.
Use semantic HTML first, such as a <label> tied to its input with a for attribute. After that, aria-labelledby is the tool for custom widgets and ARIA roles that semantic HTML can't label on its own, including comboboxes, sliders, dialogs, and similar custom controls.
Dialogs are a good example. A modal built with role="dialog" typically has a heading rendered inside it already. Pointing aria-labelledby at that heading's ID gives the dialog itself an accessible name without writing a second, duplicate piece of copy.
Tab panels, comboboxes, and similar widgets follow the same pattern: the visible label a sighted user already reads is reused as the accessible name. Getting this right also satisfies the accessible-name checks in most ADA compliance checklists.
How does aria-labelledby work?
The aria-labelledby attribute takes an ID reference list separated by spaces, so it can point to a single element or combine several elements into one accessible name.
When more than one ID is listed, the browser concatenates each referenced element's text content in the order the IDs appear in the attribute value, not the order those elements appear in the page. List the IDs in a different order and the resulting accessible name changes to match.
Referencing an element's own ID is also valid, and it lets you fold that element's own text into a name built from several sources. If an ID appears more than once in the list, browsers calculate the accessible name using only the first occurrence, ignoring the repeat.
Using aria-labelledby is one of the main ways to provide an accessible name, above other aria label attributes, any native HTML element such as <label>, and even the current element's own inner text, giving it the highest precedence of any naming method.
This precedence holds even when the referenced element is hidden from view with the HTML hidden attribute or a CSS rule like display: none and visibility: hidden – the text still counts toward the calculated name string, so it's worth checking the result in an actual screen reader rather than assuming.
Two other details are worth remembering when you are working with aria-labelledby.
- If the attribute references a form input, the current value of that input is used at the time the name is calculated – though don't rely on every browser recalculating it live when the value changes.
aria-labelledbyreferences can't be chained: if a referenced element itself carries its ownaria-labelledbyattribute, that nested reference is ignored, and the referenced element's plain text content is used instead.
Support has limits, too. Elements with the generic role, such as a plain <span> or <div>, can't use aria-labelledby unless a role that supports an accessible name is added alongside it. A handful of other roles, including presentation and none – plus several structural roles such as code and time – don't accept an accessible name at all, so aria-labelledby has no effect there.
This behavior comes from the accessible name and description computation, the algorithm browsers use to calculate accessible names and descriptions before handing them to accessibility APIs and, in turn, screen readers and other assistive technology.
An aria-labelledby example
A common use case is labeling a landmark region with a heading that's already on the page:
<h2 id="billing-heading">Billing address</h2>
<section aria-labelledby="billing-heading">
<!-- form fields -->
</section>Here, the section's accessible name becomes "Billing address" without repeating that text anywhere else in the markup.
Referencing more than one element works the same way, concatenated in the order listed:
<label id="qty-label">Quantity</label>
<input type="number" id="qty" aria-labelledby="qty-label qty-note">
<span id="qty-note">items in stock</span>A screen reader announces this input's accessible name as "Quantity items in stock," built from both referenced elements in the order their IDs appear in the aria-labelledby attribute.
A third common use case labels a dialog with its own visible heading, so the dialog title never has to be written twice:
<div role="dialog" aria-labelledby="dialog-title" aria-modal="true">
<h2 id="dialog-title">Delete this project?</h2>
<p>This action can't be undone.</p>
<button>Cancel</button>
<button>Delete</button>
</div>A screen reader announces the dialog itself as "Delete this project?, dialog" as soon as it opens, using the same heading text a sighted user already sees.
The same reference pattern also beats the title attribute for labeling SVG icons inside a button – title text is read inconsistently by screen readers and never reaches touchscreen users at all.
aria-labelledby vs. aria-label
The main difference between aria-labelledby and aria-label depends on where the label text lives.
It is not unlike how the alt attribute supplies alt text, or alternative text, for images specifically rather than pointing to text elsewhere.
As a rule, go for aria-labelledby when the label text you need is already sitting somewhere else on the page, and go for aria-label when no such text exists and you need to write one from scratch.
Common mistakes or misconceptions
- Referencing an ID that doesn't exist. A typo in the ID attribute or a reference to an element that got removed leaves the target with no accessible name at all.
- Assuming DOM order controls the result. The order that elements appear on the page has no bearing on the accessible name. Only the order of IDs listed in the
aria-labelledbyattribute controls how the text gets concatenated. - Using
aria-labelledbyon an element with no supporting role. A<span>or<div>with no role attached, or a role like presentation or generic, won't expose an accessible name even witharia-labelledbyset. Add a role that supports one first. - Expecting label-like click behavior. Unlike a native
<label>element,aria-labelledbydoesn't move focus to the associated control when its referenced text is clicked. That behavior can be added with JavaScript if required. - Reaching for
aria-labelledbywhen a simpler fix exists. If a form field already sits inside a properly associated<label>, addingaria-labelledbyrarely improves anything and just adds a second labeling mechanism you then need to keep in sync. Save it for cases native HTML genuinely can't handle.
Frequently Asked Questions
Does aria-labelledby override aria-label?
Yes. If an element has both attributes set, aria-labelledby wins, and aria-label is ignored entirely for that element's accessible name.
Can aria-labelledby reference an element that's visually hidden?
Yes. Text from an element hidden with the HTML hidden attribute or a CSS rule such as display: none still contributes to the calculated accessible name, even though sighted users never see it.
It is a handy way to give screen reader users extra context without cluttering the visible page.
Is aria-labelledby the same as using a native label element?
Not quite. A <label> element can only be tied to a single input field and moves focus to it when clicked. aria-labelledby can reference multiple elements and apply to a wider range of roles, but it doesn't move focus on click without extra scripting.
Should I use aria-labelledby or aria-describedby?
Use aria-labelledby for an element's name – what it is, announced first. Use aria-describedby for longer, supplementary detail, announced after the name, similar to additional instructions or a hint. A form field might use aria-labelledby to point to its label text, and aria-describedby to point to a nearby note explaining a formatting requirement.
Try our website monitor free
Automate website monitoring tasks
and keep your pages compliant