Usability & Accessibility

ARIA & Dynamic Content


Learning Objectives

  • You can expose changing state without relying solely on visual updates.
  • You can use native semantics before adding ARIA roles and attributes.
  • You can distinguish an appropriate announcement from an intrusive stream of updates.

Changing text on a screen is not the same as announcing that change. A person may be looking elsewhere, typing in a form, or navigating through an accessibility tree rather than watching the whole page.

Accessible Rich Internet Applications (ARIA) attributes express additional names, roles, states and relationships when native HTML does not already expose them. ARIA exposes information; it does not implement interaction. The ARIA Authoring Practices introduction explains the behavioral expectations attached to ARIA roles.

Native disclosure with details and summary

For a disclosure, details and summary provide both the interaction and its state. Try their keyboard behavior in the browser view:

index.html
<details>
<summary>Room facilities</summary>
<p>The room includes a projector and an adjustable-height desk.</p>
</details>

The browser owns keyboard activation and the open state. No duplicate Boolean, custom keyboard handler, or manual role is necessary.

Use Tab to reach Room facilities, Enter to open it, and Space to close it. Inspect the native open state and the content visibility together.

Operation feedback in a live region

A live region exposes changes to assistive technology without moving keyboard focus. This complete Svelte example keeps the status element mounted while its text changes. Its local checkReport function supplies an accepted or rejected promise:

<script lang="ts">
let fail = $state(false);
let status = $state<"idle" | "checking" | "ready" | "failed">("idle");
const messages = {
idle: "Report status has not been checked.",
checking: "Checking the report.",
ready: "The report is ready.",
failed: "The report status could not be checked.",
};
let pending = $derived(status === "checking");
const checkReport = async () => {
if (fail) throw new Error("Controlled failure");
};
const check = async () => {
if (pending) return;
status = "checking";
try {
await checkReport();
status = "ready";
} catch {
status = "failed";
}
};
</script>
<h1>Report feedback</h1>
<label>
<input type="checkbox" bind:checked={fail} />
Reject report checks
</label>
<button type="button" aria-disabled={pending} onclick={check}>Check report</button>
<p role="status" aria-atomic="true">{messages[status]}</p>

After keyboard activation, feedback changes while focus remains on Check report. Selecting the checkbox makes subsequent checks fail; clearing it allows a retry. The supplied promise settles immediately, so the example demonstrates result feedback rather than a visibly long pending period.

aria-atomic="true" asks assistive technology to present the whole status message when it changes. Keep the live-region element in the document; update its text instead of creating a new region only after the result arrives.

role="status" is suitable for a non-urgent advisory change. Reserve an assertive alert for information whose interruption is justified. On an initiating button, aria-disabled can expose pending state while keeping the control focusable, but the handler must also prevent duplicate work: the attribute alone does not stop activation. Likewise, aria-busy describes a region being updated but does not prevent duplicate requests.

The changing message should also be visible. A screen-reader-only announcement is not a replacement for feedback needed by other users.

Context and frequency of announcements

A changing number without context may not convey meaning. “3” is ambiguous; “3 matching rooms” gives context. Conversely, announcing an entire page after every small change overwhelms the task.

For frequent updates, aggregate meaningful state changes. A continuously ticking timer should not announce every second. A message that a deadline has changed is a more useful event than a stream of repeated countdown numbers.

A useful announcement unit

0 / 5 points

Queue counts change several times while a person is filling another form. Which policy deserves consideration?

Check Your Understanding

  1. What does ARIA add, and what behavior does it not implement?
  2. Which behavior and state does a native details element provide?
  3. When is a status region more appropriate than an alert?
  4. Why should a live countdown not announce every second?
  5. Why can a test for the existence of an ARIA attribute still miss an accessibility failure?