Curriculum Series

aria-label, aria-labelledby, and aria-live in practice

aria-label, aria-labelledby, and aria-live in practice

aria-label, aria-labelledby, and aria-live in practice

HTMLAccessibility

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.

javascript
<!-- 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:

javascript
<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:

javascript
<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:

javascript
<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:

javascript
<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):

javascript
<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?

javascript
<!-- 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?

javascript
<!-- 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."

Finished reading?

Mark this topic as solved to track your progress.