Live

ARIA live is perfect for announcing information about changes in state without disrupting the users focused place on the page.

The Problem

Users are not aware of stateful changes that occur outside of the their area of focus.

The Solution

Judicious use of ARIA live regions helps fill in the gaps that screen reader users would otherwise miss.

Related Articles

Live Examples

Before illustrates the problem, After illustrates the solution. Click the header to see it larger in a modal.

Please note that this Before example contains inaccessible code, use this link to skip to the After Live Example

before

after

Code Comparison

Code diff between the before and after examples above to show the changes necessary. To copy the final source click on the 'after' path link before the diff.

source

Comparing /examples/aria/live/before/index.html to /examples/aria/live/after/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Accessibility Solutions - ARIA - Live</title>
<link rel="stylesheet" href="../../../presentation.css" />
<link rel="stylesheet" href="live.css" />
</head>
<body id="top">
<main>
<h1>ARIA Live examples</h1>

<article aria-labelledby="polite-example">
<header>
<h2 id="polite-example">Polite</h2>
<p>
The most common use of ARIA live is to announce a change in state to
the user as soon as possible without interrupting. Using
<code>aria-live="polite"</code>, the message will be announced the
next time the user is idle.
</p>
</header>

<p id="polite-live-region"
role="status" aria-live="polite"></p>
<button class="polite-button">
Click here for polite examples using <code>aria-live="polite"</code>
</button>
</article>

<article aria-labelledby="assertive-example">
<header>
<h2 id="assertive-example">Assertive</h2>
<p>
Far less common but occasionally useful is to be able to announce an
important time-sensitive message by using
<code>aria-live="assertive"</code>. Please note that user agents or
assistive technologies mY choose to clear queued changes when an
assertive change occurs. (e.g., changes in an assertive region may
remove all currently queued changes).
</p>
</header>

<p id="assertive-live-region"
role="status" aria-live="assertive"></p>
<button class="assertive-button">
Click here for assertive examples using
<code>aria-live="assertive"</code>
</button>
</article>

<article aria-labelledby="relevant-example">
<header>
<h2 id="relevant-example">Relevant Only</h2>
<p>
In addition to <code>aria-live</code> allowing us to set priority of
our messaging, there is also <code>aria-relevant</code> that lets us
define what types of changes should be presented. This example
simulates a chat app where messages are appended to a growing list,
in this case it would be appropriate for only additions to be
announced to the user with <code>aria-relevant="additions"</code>.
</p>
</header>
<div role="status" aria-live="polite" aria-relevant="additions">
<ul id="relevant-live-region">
<li>
<h3>Steve:</h3>
<p>
Hey lookit that cool button down there, I wonder what that does?
</p>
</li>
</ul>
</div>
<button class="relevant-button">
add another message to chat above
</button>
</article>
</main>

<script src="live.js"></script>
</body>
</html>

javascript

Comparing /examples/aria/live/before/live.js to /examples/aria/live/after/live.js

(function () {
'use strict';

function politeExample(id) {
const messageArray = [
'Howdy, it sure looks like today is going to be a great day!',
'I appreciate all your hard work applying accessibility to your interfaces!',
"What lovely weather we're having, isn't it?",
];
const liveContainer = document.getElementById(id);
liveContainer.innerHTML = messageArray[Math.floor(Math.random() * 3)];
}

const politeButton = document.querySelector('.polite-button');
politeButton.addEventListener('click', function () {
politeExample('polite-live-region');
});

function assertiveExample(id) {
const messageArray = [
'Whoa there, something urgent just came up you should know about.',
"I'm being assertive because I have some time sensitive information.",
'This is an important message that needs to be communicated quickly.',
];
const liveContainer = document.getElementById(id);
liveContainer.innerHTML = messageArray[Math.floor(Math.random() * 3)];
}

const assertiveButton = document.querySelector('.assertive-button');
assertiveButton.addEventListener('click', function () {
assertiveExample('assertive-live-region');
});

function relevantExample(id) {
const messageArray = [
'Oh I see, clicking that button adds more messages like this one.',
'I guess that means this is a chat app, eh?',
'So what do you want to chat about?',
'How about how cool ARIA live regions are?',
'They really help fill the gaps of stateful changes to an application.',
"These examples really just scratch the surface, there's so much you can use ARIA live for!",
'Like notifying the user of results from realtime filtering.',
'Form validation errors that happen without a page refresh.',
'Even typeahead options on a combobox!',
'Anywho, I better get back to building out more content on this site',
'I appreciate you clicking through ten (oops now eleven!) messages like this',
"Perhaps you're wondering how many there are.",
'What if I told you I figured out a way to make it go infinitely',
'Is it clever AI that writes new messages realtime?',
"Of course not, ain't nobody got time for that",
'I developed a chat app memory scrambler',
"Beware, click once more and I'll forget this whole conversation ever happened!",
'Hey lookit that cool button down there, I wonder what that does?',
];
const liveContainer = document.getElementById(id);

// Using DOM methods here to generate the new HTML to ensure only the newest messages are read aloud.
const newMessage = document.createElement('li');
const newMessageName = document.createElement('h3');
newMessageName.appendChild(document.createTextNode('Steve:'));
const newMessageNameIntro = document.createElement('span');
newMessageNameIntro.className = 'sr-only';
newMessageNameIntro.appendChild(
document.createTextNode('New message from ')
);
const newMessageContent = document.createElement('p');
newMessageContent.appendChild(
document.createTextNode(messageArray[nextMessage])
);
newMessage.appendChild(newMessageNameIntro);
newMessage.appendChild(newMessageName);
newMessage.appendChild(newMessageContent);
liveContainer.appendChild(newMessage);

liveContainer.scrollTop = liveContainer.scrollHeight;
nextMessage++;
if (nextMessage === messageArray.length) {
nextMessage = 0;
}
}

let nextMessage = 0;
const relevantButton = document.querySelector('.relevant-button');
relevantButton.addEventListener('click', function () {
relevantExample('relevant-live-region');
});
})();