Understanding Live Regions
Thanks.
Hi everyone.
And welcome to understanding live regions.
Primarily intended for screenreader users, live regions are a powerful tool that make announcements every time content changes within a designated part of a webpage.
Live regions are very powerful because they allow developers to control screen readers to announce anything they want them to, whether the user wants to hear it or not.
When used properly and in moderation, Live regions can enhance the usability of your website immensely, but conversely, they can be a usability nightmare.
And can be very disruptive to a user's experience when implemented poorly.
We will now take a closer look at live regions.
We will talk about how they work, what makes them useful and how to implement them responsibly.
So imagine you're a passenger on an airplane.
Also remember airplanes, they used to be a thing.
So on the screen, you're seeing a backseat monitor in an airplane.
Mid flight, your enjoying some peanuts.
And of course watching the final minutes of the Avengers movie, the good guys are just about to save the earth from total destruction and then suddenly.
[sound of in flight annoucement alert] A popup appears on your screen.
The playback stops, your screen stops responding, and you start hearing the announcement from the flight deck or the cabin crew.
But what about the movie?
Right?
Of course, these types of interruptions are necessary for important safety announcements.
But if companies disrupt the user experience for something non-critical like the latest airline frequent flyer promotion or something, the user is going to be much less forgiving.
So think of live regions like these announcements on a loud PA system, they are helpful when used in moderation and when providing important information.
But when used frequently, they disrupt the user's ability to use and enjoy your product.
So if you're not already familiar with live regions, under the hood live regions are controlled with JavaScript and work by listening to mutations inside a, specifically designated DOM node, which is my attempt at sounding smarter, instead of just saying a deal with a bunch of ARIA attributes.
So essentially you tell the screen reader to watch a specific DOM node and every time there's a change of content within that node, these changes will be announced to the user.
Live region announcements are transient, meaning once the announcement is made, they are gone forever.
They cannot be replayed or revealed later.
But I think it is worth emphasizing again, that live regions can be disruptive.
And their use cases are very specific and limited.
When trying to provide information to your users, you don't always need a full blown announcement, whether on an airplane or on a webpage, there are always alternatives.
Sometimes all you need is to provide a small lit sign and [sound of seat belt fastened chime] the subtle chime to go with it.
Your users will get the message.
After all our main objective as developers is to convey information with minimal obstruction.
So now we know what live regions are and how they might negatively affect our users, let's see how they can be useful.
So screen readers work by linearizing content.
Essentially when the user is focused on one part of a webpage, they will not be made aware of content changes happening elsewhere.
Some examples of this might be a new chat message while the user is busy typing a response an ebook reader or a stock market ticker that periodically refreshes web content.
So loading and progress indicators, form errors and all types of counters like remaining characters or remaining time indicators are further examples of how content can change without a user realizing the page they are looking at has changed.
So features like this require a way to inform users about what's happening elsewhere.
while they are focused on a particular part of a page.
In order to better understand how live regions work, let's first, take a look at how screen readers present content.
Let me welcome you to ACME Inc's Website.
It has a very familiar Layout.
It has a header section that contains the logo, the links to about us, products, services and the contact page.
And there's a side panel, which contains links to product categories such as, and anvils, hammers, explosives.
And of course, swag.
We also seem to be on a product page featuring the beautiful ANV 2000, a professional grade anvil, and there's a form to join a sweepstakes, for a free anvil, of course.
Finally, a footer section with links to social media and CEO's poetry corner.
And if you think that's cheesy, I actually had to CEO's poetry corner for a holding website back in the nineties, man, some scars never heal.
For a sighted user a web page can be perceived in two dimensions.
And it's easier to skim through the webpage content..
Our attention will be directed to any changes within the viewport.
For example, when an error message appears on the screen a sighted user will notice the change as long as it is discernible enough.
A screen reader however works differently.
It will linearize the page, meaning the page will essentially be converted to a single dimensional form, a eryv long text string, if you will.
So a quick warning, there is heavy animation on the next slide.
So please look away for about 10 seconds if you need to.
Once linearized users can navigate between elements using the keyboard and can only hear or read one element at a time.
Think of it like listening to a cassette tape, which you can rewind fast forward, pause and play.
So this is essentially what the screen reader does.
Linearization works well for static webpages, but what happens when page content is altered with JavaScript, such as when the user action results in an error message?
Let's click the submit button and go back to the beginning, of our content where we append the error message and find out.
When I click on the submit button, an error message will be appended far, far away from the button I just clicked.
Since the error message I just inserted is just a regular DOM element, a screen reader user will have no awareness of this update.
And this is where live regions come into play.
Now let's delete the error message and insert a live region instead.
Once I insert and designate the DOM node to be a live region that specific DOM node will be checked for changes periodically.
So think of live regions as something like a livestream, everything happening inside will be announced, live like a news channel you're listening in the background.
Now every time I insert new content into the region, users will be notified of the new content regardless of their focus position on the page.
Live regions can also be configured to announce when things are removed from the live region or when there are text changes or any combinations of these, along with a bunch of other options.
So, this is essentially what live regions are and why they are called live regions.
To recap quickly, live regions are a way of creating dynamic notifications for screen reader users.
They are controlled by the website author.
Users have very little control over live regions.
They work by announcing mutations inside a designated DOM element.
And the announcements are transient once anniunced, there's no way to replay or review them.
Now that we have the basics in place, let's take a deep dive into how live regions are actually created and used.
Let's start with where to place the live region first.
Live regions can be placed anywhere in the DOM, as long as it is inside the body tag.
Any HTML tag can be used, but most commonly a generic tag such as a DIV seems to be the prevailing method.
You can also use a semantic tag such as the section element it's completely up to you.
LIve regions can be visible on the screen or hidden from visual users by using the usual hidden CSS technique, such as moving the container outside the viewport, view port and clipping content.
However, they cannot be hidden using the display or visibility property, but sometimes it's just best to keep the container visible.
In this example, let's start by adding our container to the DOM.
With this code we only have a visual hidden container and it's not a live region.
To turn this DIV into a live region, all we have to do is adding the aria-live property.
It is really that simple.
As you can see here, aria-live will exhibit different behaviors based on the value provided to it.
One of polite, assertive, or by default off.
When regions are specified as "polite", assistive technologies will notify users of updates, but generally do not interrupt the current task.
When regions are specified as "assertive" assistive technologies will immediately notify the user and can potentially clear the screen reader buffer, deleting any pending notifications.
And finally "off", which is the default value, and it will turn the announcements off unless the container is focused.
Well, this is what the ARIA spec says.
But in reality, if you put aria-live off, it's just going to turn the announcements off whether the container is focused or not.
To illustrate, you are seeing a photo of a man holding a stop sign in one hand, and a loud speaker on the other.
An assertive live region is just like holding a loudspeaker, it will grab our users' attention, whether they like it or.
When a live region is marked as assertive assistive technologies should alert the user immediately.
I put the emphasis on should because some assistive technologies allow users to tweak their live region setting.
But generally you can expect an assertive live region to be announced instantly, and by interrupting whatever there is in the screen reader buffer.
There's also another reason why I picked this image, because if you use a asseertive live regions for anything other than occasional important and essential updates, you will disorient and outright annoy your screen reader users.
So please do not be this guy.
Use your powers wisely.
On the other hand, the polite live regions are the Canadian cousin of our assertive a live region.
On the screen, you're seeing the photo of a woman, quietly whispering.
The screen reader will announced polite regions, more gracefully.
It will wait for other announcements to complete and for the user to finish interacting with other things.
Polite announcements are less obstructive, but that doesn't mean they cannot be annoying.
I'd be delighted if someone whispers in my ear that I have ketchup on my shirt, but I probably won't be as appreciative if the person does that every 30 seconds.
To sum it up, you probably want to use a polite region by default for the majority of use cases.
Use a polite region when user needs to know something.
Like when something succeeded or when there's a new chat message or to indicate loading status of a page.
Assertive regions on the other hand are limited to very few use cases.
You want them when users need to know something and act accordingly, like when there's an error or something more serious, like a session timeout or security alert.
Now that we have a live region, all we have to do is insert a new DOM node with the content into the live region.
As soon as new content is inserted, it is text content will be announced to the user.
Each insertion to the live region will trigger a new notification.
Now you may be wondering, is that all there is to live regions?
Is that it?
Well, yes and no.
Until now we've seen the basic live regions, a simple container with an aria-live property, which is very well supported by most browser, operating system and screen reader combinations.
So keeping up with the aviation theme, brace yourselves, because we are now moving into turbulent air on the screen, we see an airplane moving into a storm from the cockpit view.
I will show you some additional configuration options and alternative ways to create live regions, but keep in mind that support for what I'm about to show you is very spotty.
ARIA Specification has extra properties that gives us final control over how live regions behave.
However, support for these attributes is still spotty.
So make sure to test and don't assume these will universally work.
The first attribute is aria-relevant.
This attribute controls when an announcement is triggered.
"Additions" will trigger a notification when a DOM node is added to the region and "removals" will trigger a notification when a DOM node is removed from the region.
And "text" will trigger one calculated text alternative changes such as, just changing a text node inside or changing a text alternative for an image.
And "all" is a shorthand for all three options.
And by default live regions trigger on additions and texts.
Aria-atomic controls what is contained in the notification.
It is set to false by default, which will announce only the newly added information.
When set to true, it will cause the entire content of the region to be announced.
This is useful when you have static text in the region and you want to update a part of the region, but you want the entire content to be read such as a now playing indicator.
On the screen, you see a very good example of this.
So.
I have a span that says "now playing" and there's another span that contains the song title.
So if I only changed the song title using JavaScript, the live region is still going to announce "now playing" and the song title, because it is an atomic region.
It doesn't matter what has changed whenever there is a change.
It's going to read everything.
This is not a good idea for incrementally expanding regions, such as a chat log, but for use cases like this, like a now playing indicator, it is great.
Finally aria-busy.
It they'll pause the notifications as long as it is set to true.
So the idea here, if if your script makes multiple DOM insertions or removals on the live region, you set, aria-busy to true first, make your notifications and set it back to false so that users are not exposed to each individual update.
You are not limited to aria-live attribute to create live regions.
Some aria roles and tags are also implicit live regions.
Two most ARIA roles are alert and status.
The support for these two is pretty good.
Essentially, when you create a container with the role alert, you're actually creating an assertive and atomic live region.
One interesting quirk about role = alert is that it pretty much works on every screen reader without having to insert the container in DOM first.
You are not limited to aria-live attribute to create live regions.
Some aria roles and tags are also implicit live regions.
Two most used aria-roles are alert and status.
The support for these two is pretty good.
Essentially, when you create a container with the role alert, you're actually creating an assertive and atomic live region.
One interesting quirk about role equals alert is that it pretty much works on every single screen reader, without having to insert the container in DOM first.
You know, normally you would have to place your live region and the DOM first and then insert your notifications later.
But with roll equals alert, you can just place a container with the role alert.
And the screen reader is just going to announcement it.
There are a bunch of other live region roles, but the support is pretty spotty.
Again.
If you use these roles, it may be a good idea to add aria-live and aria-atomic attributes, even though they might seem a little redundant.
We also have the output HTML element, which is a general container for displaying calculation results.
It's also has an implicit role of status.
So most assistive technologies will recognize it as a live region.
And finally, we have progress indicators.
Well, they're not technically live regions, but I guess it's still worth mentioning because when you put a progress bar in your screen, some screen readers will either annonce the progress as a percentage value or generate sounds and tones, depending on the progress.
One trick to having robust live regions is carefully choreographing the sequence of events.
In my experience, I've found this formula to work well with most screen readers and browsers.
The most important thing is to have the live region container inserted in DOM, before inserting the notifications themselves.
Preferably you should have a single live region in your page and already in the HTML code served from the server, but it will also work if you dynamically insert the region.
Just make sure it's already a present in the DOM as early as possible.
Next, just wait, give your browser the accessibility API and the screen reader to settle.
I find that a short wait of 250 milliseconds is often enough time, but you can adjust the delay to a number that works better for you.
You might need a higher number on these pages with lots of DOM nodes.
Next, insert the message you want to be announced inside the live region container.
The caveat here is you must insert your message in one go.
Don't compose the message using multiple insertions to DOM.
It may cause screen reader to announce each insertion separately.
Compose your message in memory and insert in one fell swoop.
At this point, the screen reader should have picked the changes and start the announcement.
Now you have two options.
You can clear the live region right away or wait until the next announcement.
Just make sure to delete the live region content and wait a bit.
The most important takeaways here are making sure the live region is cleared up in between updates, waiting a bit between those updates.
And inserting everything in one, go.
Again, normally you don't have to clear contents of the live region since it gets triggered on insertions, but I find that this method has the best compatibility.
Before we continue, let's recap what we have learned so far.
Live regions are DOM nodes that svreen readers, periodically scan and announce when their contents change.
They must be present in DOM before actual notification content is inserted.
They can be polite or assertive.
They should be used in moderation.
They can be tweaked with additional attributes, but the support is spotty.
Now that we have a good understanding of what live regions are and how they work.
Let's take a look at some common examples.
You can find in the wild.
Toast Messages are very common in web design now.
They are tiny popup messages that appear on the top or the bottom of your screen.
And for most cases, they just disappear after a short while.
They can be very challenging to make accessible for so many reasons.
But if there's one component that I would pick to visually represent what live regions are, it will be the toast message.
An information toast message like the one you see on the top that says "the toast has done" is perfect to be placed in a polite live region.
You can also use an element, with the role status, if you want to use a semantically correct role.
Depending on your implementation, you can use aria-atomic property.
For example, you can use a live region with aria-atomic set to false.
This will let you use a single container and insert notifications inside.
The same goes to the error message, but we probably want to use an alert instead of status, because we want the region to be assertive.
Since role alert works very reliably, you can just insert this one directly, or use the conventional method of inserting the region first and then inserting the message.
Now, this is all good for simple toast messages, but what if toast messages are interactive like this?
So it says "the toast is on fire" and it gives us the option to eject.
And there's also now a close button in the toast message.
So what are we going to do?
When a liveregion is announced, users will have no awareness of where the live is located.
It can be buried anywhere within the DOM.
Live regions are just not a good choice for announcements with interactive elements in them.
If the notification is important enough, instead of using a live region, it is much better to just put keyboard focus on the notification container itself.
It's going to make things so much easier for assistive technology users.
Next up, the loading screen.
As single page apps gain popularity, we see these loading experience more and more in modern web design.
There's also, what's called skeleton screens where a simplified graphical representation is shown to the user until actual content loads.
Live regions can be used for notifying users that a screen has started loading and when the loading is complete.
A polite region, or a region with role "status" work great for this purpose, especially if loading takes more than a couple of seconds.
As an alternative, you could use aria-busy to indicate a section being loaded, but again, aria-busy is just not well supported.
So next stop is counts, countdowns, and timers.
Anything, that's a counter such as a remaining character indicator of a text field, or number of searches results in a search bar or a countdown timer in an online test.
They are all good candidates for live regions because you know, live regions, they don't interfere with the user.
However, what happens if you put the counter itself in the live region?
Yeah, user will be notified on every key press.
I just can't think of a worse user experience.
Remember anything that updates too frequently are just not great inside the live region.
You can solve that by adding a little bit of a logic.
So instead of updating on every key press, you can update the user at every 50 characters for example.
And once 20 characters left start updating it every five and finally when the counter hits zero use an assertive live region so that we can be sure that user got the message.
And same can be used for timers.
Just make sure not to bombard the user with notifications.
Form errors are another good use of live regions.
There are three kinds of errors that can happen on a form.
First is inline validation where a form input is verified as a user's typing.
A password fields with a strength indicator is a good example of these types of fields.
We can use a polite live region for these types of messages so that it doesn't interfere with the user.
Next is validation on blur.
This is similar to inline validation, but this time verification is done when the user leaves the field.
We can use an assertive live region for these types of situations.
And finally, there is validation on submission.
This is when the user fills out the form and clicks submit.
It is best to use an assertive live region or a container with role alert for these.
One important thing is keeping our error messages precise.
If error notification simply says "invalid entry" user may have trouble figuring out which field has an error or what needs to be done in order to fix the error.
So a message that says "invalid password field cannot be left blank" it would be a much, much better user experience.
Messaging and chat interfaces are also very common in websites.
Live regions are essential for these interfaces because as a screen reader user, I will be able to compose a response while being notified of what others are saying in the chat.
ARIA has a role of log for these types of containers, which is essentially a non atomic polite container.
So in theory, every new message inserted to the chat area should be announced individually.
But unfortunately the log role is not fully supported.
You may end up with a live container that reads the entire chat history, when a new message arrives, which is a terrible user experience.
So in reality, we need a separate live region, a polite one for this purpose and insert every incoming message one by one.
This ensures maximum compatibility on different platforms.
These were common examples of live regions and mostly good ones.
Now let's take a look at some things that you should avoid when using live regions.
And first one, assuming screen readers only output speech.
Screen readers are essentially text interfaces.
Do not assume they always output sound or speech, and don't try to design a screen reader experience.
Sometimes screen readers just don't announce the things we'd like them to.
The reason is they have a ton of internal heuristics to deal with terrible apps and websites.
Just an example.
It may pronounce WICAG as W-C-A-G instead of just saying "WICAG".
I see sometimes developers try to override that behavior by providing a phonetic alternative.
Like the one you see here.
Please never do that.
And here's the reason why.
Let me introduce you to this bad boy over here, it's called a refreshable braille display.
It connects to your screen reader on your computer or your phone.
It has electronically actuated pins that can display braille characters.
They can also have a keyboard for inputting text and braille, and they also have cool futures like ebook readers calculators.
And not taking ads.
And many screen reader users preferred these over speech output.
Persons who are deaf-blind also use these devices exclusively.
Another reason is they can also automate screen readers for automated testing now.
Just imagine how weird the test case would look when you try to make an assertion for these.
Well, live regions are not the most reliable things.
Never assume everything you put into that live region will be announced to the user.
User may hit a key on the keyboard, just a millisecond before your announcement starts.
And you're announcement goes to trash.
There may be other live regions on the page that compete.
There may be other sounds on the page or in the room, like a video playing.
Someone might ping the user on slack while your announcement is being read.
So do not rely on live regions to convey important things.
There's really no shame in using a javaScript alert.
Another important thing.
Don't wrap sections or components in a live region.
It will be a terrible user experience for your screen reader users.
First updates to larger sections of the page, such as a sortable data table, or a long form is super tricky to predict.
You can't be sure what gets added or removed, and therefore what's being announced to the user.
Although we have fine control over live regions, using aria-atomic and aria-relevant properties support for those are poor.
Using a separate, simple live region where insertions are tightly controlled by the developer is still the most widely supported approach to live regions.
If you have multiple live regions on a page, they may interfere with each other.
Some may be polite, some may be assertive and they may fire at unpredicable times.
This causes some messages to get lost, or just partial announced.
To avoid this, just minimize the number of live regions you have on a page.
One good approach is to have one polite and one assertive region that gets inserted to the page in the beginning and shared by other components on the page.
This allows you to manage the message queue more efficiently and avoids race conditions.
Another trend I'm starting to say in modern, single page apps where a page's loaded in the background without refreshing the page is using live to announce page titles.
On a regular page when a user clicks on the link and navigates to a new page, screen readers will announced the title of the new page, so that users know where they have landed.
This doesn't happen in a single page app so many single page app frameworks resort to using live regions instead.
But live regions are unpredictable.
So instead of relying on a live region to announce the page changes alone, also make sure to manage focus and send keyboard focus to somewhere on the page.
Like a top level heading in the new page to signal the user that the new page is loaded.
Don't forget to update the actual page title too.
Another thing I'm seeing is using live regions to convey state changes in a component like when a dropdown menu is expanded or when a toggle switch is activated.
The problem here is live region announcements are changing when I move away and focus back on the component without changing its state, I will have no indication of the current status.
Live regions are not substitutes for ARIA properties, that convey role state and value.
Another common mistake, especially in previous generations of web applications, is composing in DOM.
This means making multiple insertions to actual DOM to create content.
This is bad for performance and so many other reasons, but it is also no good when working with live regions.
In the code example here, author is inserting two divs into a live region.
One says hello, and the other says world.
You might expect the screen reader to say hello world.
But in reality, it will probably just skip the first update, hello, and just say World.
To avoid this, compose your messages and memory by using a variable, and insert the entire message at once.
So, this is less of an issue nowadays, thanks to modern JavaScript frameworks, such as React that use a virtual DOM and smart diffing to make controlled modifications to DOM.
But it doesn't mean that modern frameworks always gets these updates right.
So it is important to test with a screen reader and use some tools to debug.
And that brings us to debugging live regions.
And there are some common culprits that you could check to see if they are causing the problem.
If you have multiple regions on a page, they may be competing against each other.
When Iive regions make announcements at roughly the same time, they can just cancel ech other.
And another thing to look for is text computation.
If you insert any elements with aria-label, aria-labelledby, an image with alt text or anything that can affect or overwrite text computation make sure they work.
Another culprit are non-text elements like a button, an image, or a form field.
These don't really get along well with live regions.
Again, any interactive things within a live region will probably not work.
Also if content you insert have CSS classes that contain display: none or visibility equals hidden, they will not be announced.
The screen reader itself may also be causing the issues.
Remember live regions are merely recommendations to the screen reader to make an announcement.
And guess what?
They have no obligation to honor that request.
And bad mutations, not the viral kind I hope.
If you make too many complex modifications at once, that may also cause some issues.
And finally, I don't know, sometimes they just don't work, call it what you will.
And essentially, part of debugging live regions is seeing what goes inside in them and when.
And to do that we could use some tools.
First is the developer tools in your browser.
When you inspect the live region element, you can add a break on subtree modifications that will pause the script execution every time content is modified.
It makes it super easy to see what gets inserted, and by which script.
You can also log changes to your console by using a mutation observer.
Mutation observers can be attached to any DOM node and they'll fire every time there is a modification on that element.
You can see a very simple example on the screen.
You can use the snippet to log every mutation that happens on a given DOM node.
And finally a browser extension.
It is called NerdeFocus and was developed by yours truly.
You can find it in the Chrome store.
It is essentially a mutation observer on steroids, with a nice UI.
It will list all the Live regions on a page when it live regions is created and gets removed from the DOM.
Or any updates made on them, like a property change or a content change.
And it's gonna tell you when it's happened.
Again, you can find it in the Chrome store.
So that's all I have for today.
Thank you very much for listening.
If you have any comments or questionsi'm on Twitter, my handle is wizzyfx.
It's W-I -Z-Z-Y-F-X, feel free to reach out anytime.
Thanks again, and have a wonderful day.