aria-label, aria-labelledby, and aria-live in practice
Why these three come up
If you're interviewing at a company that takes accessibility seriously, expect questions on ARIA. These three attributes are the ones that come up most often — and once you see the specific problem each one is designed to solve, they click quickly.
aria-label
aria-label gives a screen reader a name for an element when there's no visible text to use. The textbook case is an icon-only button — think the little X on a modal dialog.
<!-- Without aria-label, screen reader just says "button" --><button><svg><!-- X icon --></svg></button><!-- With aria-label, screen reader says "Close dialog button" --><button aria-label="Close dialog"><svg><!-- X icon --></svg></button>
Real-world shapes you've seen a hundred times:
<button aria-label="Search"><svg><!-- Magnifying glass icon --></svg></button><button aria-label="Add to cart"><svg><!-- Shopping cart icon --></svg></button>
One gotcha that trips candidates up: if an element has both visible text and aria-label, the screen reader reads only the aria-label. So don't double up without thinking.
aria-labelledby
Instead of duplicating a label, aria-labelledby points to existing text on the page via its id. That way you keep the sighted and screen-reader experiences in sync by design.
A dialog labelled by its heading:
<div role="dialog" aria-labelledby="dialog-title"><h2 id="dialog-title">Delete Account</h2><p>This action cannot be undone.</p><button>Delete</button><button>Cancel</button></div>
No duplicate string to keep in sync. You can also reference multiple ids:
<span id="first-name">First Name</span><span id="required">(required)</span><input aria-labelledby="first-name required" />
The screen reader reads them concatenated: "First Name (required)".
Interview framing: when asked for the difference between aria-label and aria-labelledby, the one-line answer is: aria-labelledby ties the accessible name to existing visible text, so updating the UI automatically updates the announcement.
aria-live
Now the interesting one. Imagine a client-side form that shows a validation error when the user types an invalid email. A sighted user sees the red message appear — but a screen reader user gets nothing unless you tell it to announce the change.
That's what aria-live does: it marks a region as "live" so screen readers notice updates.
Two values to know:
aria-live="polite" — announces when the user is idle. This is the default choice.
aria-live="assertive" — interrupts the user. Reserve it for genuinely urgent information like "Your session is about to expire."
A form-validation example:
<form><label for="email">Email</label><input type="email" id="email" /><!-- This div will announce changes to screen readers --><div aria-live="polite" role="status"></div></form><script>const input = document.getElementById('email');const status = document.querySelector('[aria-live]');input.addEventListener('blur', () => {if (!input.value.includes('@')) {status.textContent = 'Please enter a valid email';}});</script>
When the text updates, the screen reader announces the error without the user having to hunt for it.
A loading-state example (this one is very common in interviews):
<button id="submit">Submit</button><div aria-live="polite"><span id="status">Ready</span></div><script>document.getElementById('submit').addEventListener('click', async () => {const status = document.getElementById('status');status.textContent = 'Submitting...';await submitForm();status.textContent = 'Success! Form submitted.';});</script>
Two companion attributes
aria-atomic — announce the whole region or just what changed?
<!-- Announces "Items in cart: 4" (the whole thing) --><div aria-live="polite" aria-atomic="true">Items in cart: <span id="count">3</span></div><!-- Announces just "4" (only what changed) --><div aria-live="polite" aria-atomic="false">Items in cart: <span id="count">3</span></div>
aria-relevant — which kinds of changes trigger an announcement?
<!-- Only announce when text changes or nodes are added --><div aria-live="polite" aria-relevant="additions text"><!-- Updates here get announced --></div>
A clean interview answer
aria-label: "Supplies an accessible name for elements without visible text — typical case is an icon-only button."
aria-labelledby: "References existing visible text by id. Better than aria-label because the visual and assistive experiences stay in sync automatically — e.g., using a dialog's heading as its accessible name."
aria-live: "Declares a live region so dynamic content gets announced. polite for most things; assertive only for urgent interruptions. Crucially, the container must exist in the DOM before you update it — otherwise nothing is announced."