It’s one thing to create a web application and quite another to create an accessible web application. That’s why Heydon Pickering, both author and editor at Smashing Magazine, wrote an eBook Apps For All: Coding Accessible Web Applications, outlining the roadmap for the accessible applications we should all be making.
The following is an extract from the chapter “It’s Alive” from Heydon’s book, which explores how to use ARIA live regions. Javascript applications are driven by events and the user should be informed of what important events are happening in the interface. Live regions help us provide accessible messaging systems, keeping users informed of events in a way that is compatible with assistive technologies.
Getting The Message
Picture the scene: it’s a day like any other and you’re at your desk, enclosed in a semicircular bank of monitors that make up your extended desktop, intently cranking out enterprise-level CSS for MegaDigiSpaceHub Ltd. You are one of many talented front-end developers who share this floor in your plush London office.
Further Reading on SmashingMag:
- The WAI Forward
- Notes On Client-Rendered Accessibility
- Accessibility: Improving The UX For Color-Blind Users
- Making Accessibility Simpler, With Ally.js
- Inclusive Front-End Design Patterns, A New Smashing Book
You don’t know it, but a fire has broken out on the floor below you due to a “mobile strategist” spontaneously combusting. Since no expense was spared on furnishing the office with adorable postmodern ornaments, no budget remained for installing a fire alarm system. It is up to the floor manager in question to travel throughout the office, warning individual departments in person.
He does this by walking silently into each room, holding a business card aloft with the word “fire” written on it in 12pt Arial for a total of three seconds, then leaving. You and the other developers — ensconced behind your monitors — have no idea he even visited the room.
What I cover in my eBook is, for the most part, about making using your websites and applications accessible. That is, we’re concerned with everyone being able to do things with them easily. However, it is important to acknowledge that when something is done (or simply happens), something else will probably happen as a result: there are actions and reactions.
“When one body exerts a force on a second body, the second body simultaneously exerts a force equal in magnitude and opposite in direction to that of the first body.”– Newton’s third law of motion (Newton’s laws of motion, Wikipedia)
Providing feedback to users, to confirm the course they’ve taken, address the result of a calculation they’ve made or to insert helpful commentary of all sorts, is an important part of application design. The problem which needs to be addressed is that interrupting a user visually, by making a message appear on screen, is a silent occurrence. It is also one which — in the case of dialogs — often involves the activation of an element that originates from a completely remote part of the document, many DOM nodes away from the user’s location of focus.
To address these issues and to ensure users (unlike the poor developers in the introductory story) get the message, ARIA provides live regions. As their name suggests, live regions are elements whose contents may change in the course of the application’s use. They are living things, so don’t always stand still. By adorning them with the appropriate ARIA attributes, these regions will interrupt the user to announce their changes as they happen.
In the following example, we will look at how to alert users to changes which they didn’t ask for, but — like the building being on fire — really ought to know about anyway.
Alert!
Perhaps the only thing worse than a fire that could happen to the office of a web development company would be losing connectivity to the web. Certainly, if I was working using an online application, I’d like to know the application will no longer behave in the way I expect and perhaps store my data properly. This is why Google Mail inserts a warning whenever you go offline. As noted in Marco Zehe’s 2008 blog post, Google was an early adopter of ARIA live regions.
We are going to create a script which tests whether the user is online or off and uses ARIA to warn screen reader users of the change in this status so they know whether it’s worth staying at their desk or giving up and going for a beer.
The Setup
For live regions, ARIA provides a number of values for both the role
and aria-live
attributes. This can be confusing because there is some crossover between the two and some screen readers only support either the role
or aria-live
alternatives. It’s OK, there are ways around this.
At the most basic level, there are two common types of message:
- “This is pretty important but I’m going to wait and tell you when you’re done doing whatever it is you’re doing.”
- “Drop everything! You need to know this now or we’re all in big trouble. AAAAAAAAAAGHH!”
Mapped to the respective role
and aria-live
attributes, these common types are written as follows:
- “This is pretty important but I’m going to wait and tell you when you’re done doing whatever it is you’re doing.” (
aria-live="polite"
orrole="status"
) - “Drop everything! You need to know this now or we’re all in big trouble. AAAAAAAAAAGHH.” (
aria-live="assertive"
orrole="alert"
)
When marking up our own live region, we’re going to maximize compatibility by putting both of the equivalent attributes and values in place. This is because, unfortunately, some user agents do not support one or other of the equivalent attributes. More detailed information on maximizing compatibility of live regions is available from Mozilla.
Since losing internet connectivity is a major disaster, we’re going to use the more aggressive form.
<div id="message" role="alert" aria-live="assertive" class="online">
<p>You are online.</p>
</div>
The code above doesn’t alert in any way by itself — the contents of the live region would have to dynamically change for that to take place. The script below will run a check to see if it can load test_resource.html every three seconds. If it fails to load it, or it has failed to load it but has subsequently succeeded, it will update the live region’s class
value and change the wording of the paragraph. If you go offline unexpectedly, it will display <p>There’s no internets. Time to go to the pub!</p>
.
The change will cause the contents of that #message
live region to be announced, abruptly interrupting whatever else is currently being read on the page.
// Function to run when going offline
var offline = function() {
if (!$('#message').hasClass('offline')) {
$('#message') // the element with [role="alert"] and
[aria-live="assertive"]
.attr('class', 'offline')
.text('There\'s no internets. Go to the pub!');
}
}
// Function to run when back online
var online = function() {
if (!$('#message').hasClass('online')) {
$('#message') // the element with [role="alert"] and
[aria-live="assertive"]
.attr('class', 'online')
.text('You are online.');
}
}
// Test by trying to poll a file
function testConnection(url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
online();
}
xmlhttp.onerror = function() {
offline();
}
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
// Loop the test every three seconds for "test_resource.html"
function start() {
rand = Math.floor(Math.random()*90000) + 10000;
testConnection('test_resource.html?fresh=' + rand);
setTimeout(start, 3000);
}
// Start the first test
start();
There are more comprehensive ways to test to see if your application is online or not, including a dedicated script called offline.js, but this little one is included for context. Note that some screen readers will prefix the announcement with “Alert!”, so you probably don’t want to include “Alert!” in the actual text as well, unless it’s really, really important information.
There is a demo of this example available.
test.css
We would like to maximize compatibility of live regions across browsers and assistive technologies. We can add a rule in our test.css to make sure equivalent attributes are all present like so:
[role="status"]:not([aria-live="polite"]),
[role="alert"]:not([aria-live="assertive"]) {
content: 'Warning: For better support, you should include
a politeness setting for your live region role using the
aria-live attribute';
}
[aria-live="polite"]:not([role="status"]),
[aria-live="assertive"]:not([role="alert"]) {
content: 'Warning: For better support, you should
include a corresponding role for your aria-live
politeness setting';
}
I Want The Whole Story
"Taken out of context, I must seem so strange." – Fire Door by Ani DiFranco
By default, when the contents of a live region alter, only the nodes (HTML elements, to you and me) which have actually changed are announced. This is helpful behavior in most situations because you don’t want a huge amount of content reread to you just because a tiny part of it is different. In fact, if it’s all read out at once, how would you tell which part had changed? It would be like the memory tray game where you have to memorize the contents of a tray to recall which things were removed.
In some cases, however, a bit of context is desirable for clarification. This is where the aria-atomic
attribute comes in. With no
aria-atomic
set, or with an aria-atomic
value of false
, only the elements which have actually changed will be notified to the user. When aria-atomic
is set to true
, all of the contents of the element with aria-atomic
set on it will be read.
The term atomic is a little confusing. To be true
means to treat the contents of this element as one, indivisible thing (an atom), not to smash the element into little pieces (atoms). Whether or not you think atomic is a good piece of terminology, the expected behavior is what counts and it is the first of the two behaviors which is defined.
Gez Lemon offers a great example of aria-atomic
. In his example, we imagine an embedded music player which tells users what the currently playing track is, whenever it changes.
<div aria-live="polite" role="status" aria-atomic="true">
<h3>Currently playing:</h3>
<p>Jake Bugg — Lightning Bolt</p>
</div>
Even though only the name of the artist and song within the paragraph will change, because aria-atomic
is set to true
the whole region will be read out each time: “Currently playing: Jake Bugg — Lightning Bolt”. The “Currently playing” prefix is important for context.
Note that the politeness setting of the live region is polite
not
assertive
as in the previous example. If the user is busy reading something else or typing, the notification will wait until they have stopped. It isn’t important enough to interrupt the user, not least because it’s their playlist: they might recognize all the songs anyway.
The aria-atomic
attribute doesn’t have to be used on the same element that defines the live region, as in Lemon’s example. In fact, you could use aria-atomic
on separate child elements within the same region. According to the specification:
“When the content of a live region changes, user agents SHOULD examine the changed element and traverse the ancestors to find the first element with aria-atomic
set, and apply the appropriate behavior.”
This means we could also include another block within our live region to tell users which track is coming up next.
<div aria-live="polite" role="status">
<div aria-atomic="true">
<h3>Currently playing:</h3>
<p>Jake Bugg — Lightning Bolt</p>
</div>
<div aria-atomic="true">
<h3>Next in queue:</h3>
<p>Napalm Death — You Suffer</p>
</div>
</div>
Now, when Jake Bugg’s Lightning Bolt is nearing an end, we update the <p>
within the next in queue block to warn users that Napalm Death are ready to take the mic: “Next in queue: Napalm Death — You Suffer”. As Napalm Death begin to play, the currently playing block also updates with their credentials and at the next available juncture the user is reminded that the noise they are being subjected to is indeed Napalm Death.
aria-busy
I was a bit mischievous using Napalm Death’s You Suffer as an example track because, at 1.316 seconds long, the world’s shortest recorded song would have ended before the live region could finish telling you it had started! If every track was that short, the application would go haywire.
In cases where lots of complex changes to a live region must take place before the result would be understandable to the user, you can include the aria-busy
attribute. You simply set this to true
while the region is busy updating and back to false
when it’s done. It’s effectively the equivalent of a loading spinner used when loading assets in JavaScript applications.
Usually you set aria-busy=“true”
before the first element (or addition) in the live region is loaded or altered, and false
when the last expected element has been dealt with. In the case of our music player example, we’d probably want to set a timeout of ten seconds or so, making sure only music tracks longer than the announcement of those tracks get announced.
$('#music-info').attr('aria-busy', 'true');
// Update the song artist & title here, then...
setTimeout(function() {
$('#music-info').attr('aria-busy', 'false');
}, 10000);
Buy The eBook
That concludes your extract from “It’s Alive!”, a chapter which goes on to explore the intricacies of designing accessible web-based dialogs. But that’s not all. There’s plenty more about creating accessible experiences in the book, from basic button control design to ARIA tab interfaces and beyond. Reviews for the eBook and purchasing options are available here. The inimitable Bruce Lawson has written a lovely post about it, too.