The Silent Announcers: Mastering ARIA Live Regions

  • a11y
  • accessibility
  • aria
  • html
  • live regions
Jun 18, 2024
Discover how ARIA attributes can breathe life into your dynamic web content, making it accessible and engaging.

The Invisible Broadcast

Imagine a world where every change on your screen whispers directly to those who rely on its voice—the screen readers. As our web experiences become more dynamic and interactive, ensuring that these updates don’t go unnoticed is crucial. Enter ARIA Live Regions—your secret weapon for making web interactions inclusive and seamless.

In this journey, we’ll uncover how ARIA live regions can transform your web applications, ensuring that every dynamic update is heard loud and clear by all users. Armed with VoiceOver on MacOS and Safari as our trusty companions, we’ll navigate through this accessibility enhancement together.


Bringing the Weather to Life

Let’s kick things off with a simple yet powerful example—a weather application that fetches real-time data from Open-Meteo. Picture this: a span element updating with the latest temperature, all while keeping accessibility front and center.

<script type="module">
	// @ts-check

	const getWeather = async () => {
		const p = document.querySelector("p");
		const span = document.querySelector("span");

		if (p && span) {
			span.textContent = "loading...";
			const res = await fetch(
				"https://api.open-meteo.com/v1/forecast?latitude=43&longitude=-86&current=temperature",
			);
			const { current } = await res.json();
			span.textContent = `${current.temperature} degrees.`;
		}
	};

	const button = document.querySelector("button");
	if (button) button.addEventListener("click", getWeather);
</script>

<h1>aria-live</h1>

<p>
	The current temperature is
	<span>unknown. Select "Get Weather" to fetch the current temperature.</span>
</p>

<button class="button button-primary">Get Weather</button>

At first glance, clicking the “Get Weather” button updates the temperature. But what about our friends using screen readers? Without a hint, these changes might fly under the radar. That’s where ARIA live regions step in.

The Magic of aria-live

The aria-live attribute is more than just a label—it’s a gatekeeper for accessibility. It designates an element as a live region, signaling screen readers to announce any content updates within. Think of it as turning on the subtitles for dynamic content.

There are three flavors of aria-live:

  1. off - The default setting; silent as the night.
  2. polite - Announces changes once the current reading session winds down.
  3. assertive - Shouts out changes immediately, cutting through any ongoing narration.

Let’s weave this into our weather app by adding aria-live="polite" to our p tag.

<p aria-live="polite">
	The current temperature is
	<span>unknown. Select "Get Weather" to fetch the current temperature.</span>
</p>

Now, when “Get Weather” is clicked, the screen reader gracefully announces:

loading…

30.1 degrees.

aria-atomic: The Whole Story

Sometimes, partial updates miss the mark. What if we want the entire sentence to be read, not just the changing span? Enter aria-atomic.

<p aria-live="polite" aria-atomic="true">
	The current temperature is
	<span>unknown. Select "Get Weather" to fetch the current temperature.</span>
</p>

With aria-atomic="true", the screen reader captures the complete narrative:

The current temperature is loading…

The current temperature is 30.1 degrees.

Keeping It Smooth with aria-busy

Imagine if the update happens before the screen reader finishes narrating “The current temperature is loading…” It could cut off abruptly. To ensure smooth transitions, aria-busy becomes our moderator.

Here’s how we implement it:

const getWeather = async () => {
	const p = document.querySelector("p");
	const span = document.querySelector("span");

	if (p && span) {
		p.ariaBusy = "true";
		span.textContent = "loading...";
		const res = await fetch(
			"https://api.open-meteo.com/v1/forecast?latitude=43&longitude=-86&current=temperature",
		);
		const { current } = await res.json();
		p.ariaBusy = "false";
		span.textContent = `${current.temperature} degrees.`;
	}
};

With aria-busy toggled during the fetch operation, the screen reader focuses solely on the final update, ensuring clarity:

The current temperature is 30.1 degrees.

Wrapping Up

Accessibility isn’t just a checkbox—it’s a commitment to inclusivity. ARIA live regions empower us to create dynamic web experiences that resonate with everyone. By thoughtfully implementing these attributes, we’re not just enhancing functionality; we’re crafting a web that’s truly for all.