Dynamic content and ARIA
Compute names and descriptions
Understand how text, labels, aria-label, aria-labelledby, and aria-describedby combine or override one another.
Every control has two text properties in the accessibility tree. The accessible name is what identifies it: “Register”, “Email”, “Remove guest”. The accessible description is optional extra context. A screen reader reads the name right away and the description after a short pause. Voice control software matches what you say against the name.
The browser computes both from several sources, in a fixed order. Knowing that order is what stops ARIA from hiding text you wanted people to hear.
Where the name comes from
For a given element the browser tries these in order and stops at the first one that produces text:
aria-labelledby, pointing at other elementsaria-label, a string attribute- the native source: a
labelfor inputs,altfor images, the content for buttons and links title, as a last resort
Notice that aria-label beats the button’s own text. That’s the trap on the flawed page:
<button type="submit" aria-label="Submit">Register</button>
Sighted users see “Register”. Screen reader users hear “Submit”. A voice control user says “click Register” and nothing happens, because no control has that name. WCAG 2.5.3 Label in Name (Level A) exists for this case: the visible text must be part of the accessible name.
Delete the attribute and the button’s contents become the name again.
Add a description, keep the name
The page needs to tell people about the cancellation deadline before they commit. The wrong move is to stuff it into the name. The right one is aria-describedby:
<button type="submit" aria-describedby="cancel-policy">Register</button>
<p id="cancel-policy">Free cancellation until 7 October 2026.</p>
In the Chrome Accessibility pane the button now reads:
Name: "Register"
from contents
Description: "Free cancellation until 7 October 2026."
from aria-describedby
VoiceOver says “Register, button” and, after a pause, “Free cancellation until 7 October 2026”. The name stays short and matches the screen. The context is there for anyone who waits for it.
When aria-label is the right tool
Some controls have no visible text at all. The Remove button on each guest row is just an icon:
<button type="button" aria-label="Remove guest Sara Conti">
<svg aria-hidden="true">...</svg>
</button>
Here aria-label is correct, because there’s nothing visible to contradict. Including the guest’s name means a screen reader user hears which row they’re about to remove, instead of “Remove, button” five times in a list. The aria-hidden on the SVG keeps its internals out of the tree.
Prefer visible text
My default is: if text is on screen, make it the name with label, alt or plain content. Reach for aria-labelledby when the visible text lives somewhere else on the page. Reach for aria-label only when nothing is visible. Then open the inspector and read the computed name, because what you meant and what the browser computed aren’t always the same.
Try this on your page: inspect ten interactive elements and compare the computed name with the visible label of each. Fix every one that differs.
Lesson completed