Accessible notifications with ARIA Live Regions (Part 1)
Articles & Blogs

Accessible notifications with ARIA Live Regions (Part 1)

Jan 14, 2024

<p>In this chapter, we’re going to learn about ARIA live regions — the accessible notifications system that enables us to make <strong>dynamic</strong> web content more accessible to screen reader users.</p> <p>Without live regions, some rich web applications would be more challenging to use for screen reader users. So if you’re building web applications such as Single Page Applications (SPAs), you need to understand live regions so that you can utilize them <strong>where appropriate</strong>.</p> <p>This chapter is split into two parts. In <strong>this first part</strong>, we’re going to learn about why ARIA live regions are important, and the different ARIA attributes and roles that you can use to create them. We’re going to get an overview of these attributes, as well as learn about their current support landscape and limitations.</p> <p>In <a href="https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-2">the second part</a>, we’re going to get more practical and discuss why you should <em>not</em> use live regions as much as you might think that you do, and we’ll talk about alternative approaches you should use instead when you create some common UI patterns. And then we’ll discuss best practices for implementing more robust live regions when you need them today.</p> <p>But first, in order to understand <em>why</em> live regions are important, <strong>we must first understand how a screen reader parses web content and presents it to the user.</strong> We won’t get into much detail (not at all, really!), just enough to get a good understanding of what problem live regions solve.</p> <h2 id="how-screen-readers-parse-web-content" tabindex="-1">How screen readers parse web content</h2> <p>The way screen readers parse and present web content to their users is very different to how sighted users see that content.</p> <p>Screen readers work by <strong>linearizing web content.</strong> Linearizing a page’s content means converting the page’s two-dimensional content into <strong>a one-dimensional string</strong> (that is then either spoken to the user using text-to-speech, or delivered to them via a refreshable braille display).</p> <figure class="wide"> <picture><source type="image/webp" srcset="https://www.sarasoueidan.com/assets/images/two-to-one-dimension-600w.webp 600w, https://www.sarasoueidan.com/assets/images/two-to-one-dimension-900w.webp 900w, https://www.sarasoueidan.com/assets/images/two-to-one-dimension-1500w.webp 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><source type="image/jpeg" srcset="https://www.sarasoueidan.com/assets/images/two-to-one-dimension-600w.jpeg 600w, https://www.sarasoueidan.com/assets/images/two-to-one-dimension-900w.jpeg 900w, https://www.sarasoueidan.com/assets/images/two-to-one-dimension-1500w.jpeg 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><img alt="" class="undefined" loading="lazy" decoding="async" src="https://www.sarasoueidan.com/assets/images/two-to-one-dimension-600w.jpeg" width="1500" height="558" /></picture> </figure> <p>When content is linearized, it is presented to the user <strong>one item at a time.</strong> <q>You can think of it like listening to a cassette tape</q>, says Web accessibility specialist Ugi Kutluoglu, <q>which you can rewind, fast forward, pause and play.</q> This means that a screen reader user can skip to items or sections they want, and they can tab through interactive elements and Shift-tab their way back. But at the end of the day, they can only move forwards or backwards, <strong>one item at a time</strong>, because what they are presented with is a one-dimensional version of the page.</p> <h2 id="why-we-need-an-accessible-notification-system-for-screen-reader-users" tabindex="-1">Why we need an accessible notification system for screen reader users</h2> <p>Reading content linearly works well for static webpages, but it doesn’t work so well for pages where content is altered and updated dynamically or asynchronously using JavaScript. If the user can only move in one dimension, and focus on one item at a time, how would they know when content is added, removed, or modified <strong>somewhere else</strong> on the page?</p> <p>For example, when a user sends an email in most email web apps, a status message is shown at the top of the screen, or a “toast” message pops up (typically at the bottom of the screen) to notify them of the status of their interaction — for example that the email is sending, has been sent, or maybe that the email could <em>not</em> be sent. Some of these messages are urgent (like an error message), and some of them are not (like a success message, or a Draft Saved notification).</p> <p>When these status messages appear, they are intended to be communicated to all users. But while these messages may be perceivable by a sighted user, they’re not preceivable by a blind screen reader user. When the status message is shown, it is not communicated to screen reader users by default because the screen reader focus is on another element at that moment (on the ‘Send Email’ button in this case).</p> <figure class="wide"> <!-- <img src="../../assets/images/chapter--live-regions/gmail-notification.jpg" alt=""> --> <picture><source type="image/webp" srcset="https://www.sarasoueidan.com/assets/images/gmail-notification-600w.webp 600w, https://www.sarasoueidan.com/assets/images/gmail-notification-900w.webp 900w, https://www.sarasoueidan.com/assets/images/gmail-notification-1500w.webp 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><source type="image/jpeg" srcset="https://www.sarasoueidan.com/assets/images/gmail-notification-600w.jpeg 600w, https://www.sarasoueidan.com/assets/images/gmail-notification-900w.jpeg 900w, https://www.sarasoueidan.com/assets/images/gmail-notification-1500w.jpeg 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><img alt="" class="undefined" loading="lazy" decoding="async" src="https://www.sarasoueidan.com/assets/images/gmail-notification-600w.jpeg" width="1500" height="615" /></picture> </figure> <p>Here is what happens when I use NVDA and activate the Send Email button and show a status message in a dummy email app demo I created. NVDA does not announce the status message when it is shown.</p> <figure class="wide"> <video class="video-gif" controls="" src="https://www.sarasoueidan.com/assets/images/chapter--live-regions/nvda-no-announcement.mp4" width="100%"> Sorry, your browser doesn't support embedded videos. </video> </figure> <p>Here is a dummy email app demo you can try for yourself.</p> <figure class="wide"> <p class="codepen" data-height="512.5320434570312" data-default-tab="result" data-slug-hash="YzdByMb" data-user="SaraSoueidan" data-token="ee77a329a6469d35ca73d58136cf4ebc" style="height: 512.5320434570312px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/YzdByMb/ee77a329a6469d35ca73d58136cf4ebc"> Live region status message in email web app</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script> <figcaption> <p>If you activate the Send Email button in <a href="https://codepen.io/pen/debug/YzdByMb/ee77a329a6469d35ca73d58136cf4ebc">the debug version of the dummy email app</a>, the screen reader will <em>not</em> announce the status message that is shown.</p> </figcaption> </figure> <p><strong>A screen reader can only focus on one element or part of the page at a time.</strong> This means that if the user presses a button and that button triggers an update somewhere else on the page, <strong>there’s a good chance they will be oblivious to it</strong>. So they need a way to be notified of these updates when they happen.</p> <!-- There may also be auto-updating elements on the page such as countdowns, or a loading indicator which updates when the element is loading or done loading. These elements update while the user is doing something else on the page. So, they won't know what the status of these elements is unless they are somehow made aware of them. Form success and error messages like the ones we saw in the previous chapter are also an example of updates that are also not automatically conveyed to screen reader users. --> <p>There are two primary ways you make a screen reader announce an update when it happens:</p> <ol> <li>By <strong><em>moving</em> focus</strong> to where the update has happened, (like we did with the summary of error messages in <a href="https://practical-accessibility.today/chapters/form-validation-2/">the accessible form validation chapter</a>);</li> <li>By <strong>notifying</strong> the screen reader of these updates when they happen.</li> </ol> <p>When you move the user’s focus to an element, screen readers typically announce the element to the user. But when an update happens and you don’t move the user’s focus to it, you must notify screen readers in some other way.</p> <h2 id="status-messages-in-wcag" tabindex="-1">Status messages in WCAG</h2> <p>WCAG <a href="https://www.w3.org/WAI/WCAG21/quickref/?showtechniques=413#status-messages">Success Criterion <strong>4.1.3 Status Messages (Level AA)</strong></a> states that:</p> <blockquote> <p>In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus.</p> </blockquote> <p><a href="https://www.w3.org/TR/WCAG21/#dfn-status-messages">A status message is defined in the specification</a> as <q>change in content that is not a change of context, and that provides information to the user on the success or results of an action, on the waiting state of an application, on the progress of a process, or on the existence of errors.</q></p> <aside role="note"> <p>Examples of a <strong>change of context</strong> are opening a new window, <strong>moving focus to a different component</strong>, going to a new page (including anything that would look to a user as if they had moved to a new page) or significantly re-arranging the content of a page.</p> </aside> <p>From the <a href="https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html">Understanding Status Messages page</a>:</p> <blockquote> <p>This Success Criterion specifically addresses scenarios where new content is added to the page without changing the user’s context. Changes of context, by their nature, interrupt the user by taking focus. They are already surfaced by assistive technologies, and so have already met the goal to alert the user to new content. As such, messages that involve changes of context do not need to be considered and are not within the scope of this Success Criterion.</p> </blockquote> <p>In other words, this success criterion aims to ensure that, unless you move the user’s focus or cause another change of context like a page refresh, you must ensure that status messages are communicated to screen reader users using the appropriate roles and properties. To do that, you currently need ARIA live regions.</p> <h2 id="what-are-aria-live-regions%3F" tabindex="-1">What are ARIA live regions?</h2> <p>ARIA live regions are <strong>a specific type of notification system primarily surfaced for screen reader users.</strong> Using live regions, you can communicate content updates down to the accessibility layer so that screen readers are made aware of these updates when they happen.</p> <p>On an implementation level, a <strong>live region</strong> (<strong>not to be confused with the <code>region</code> landmark</strong>) is an element on the page that has been designated as being “live”. When an element is designated as a live region, <strong>a screen reader is notified when any updates take place within the element (and its children), wherever its focus is at the time.</strong></p> <p><q>Think of live regions as something like a livestream</q> says Web accessibility specialist Ugi Kutluoglu, <q>everything happening inside will be announced live like a news channel you’re listening to in the background.</q></p> <p>Using live regions, you can mark up status messages and other similar updates so that they are communicated to screen reader users.</p> <p>Here is our email notification example again with ARIA live regions working. Notice how when the ‘Send Email’ button is activated, NVDA announces the contents of the status message that is shown:</p> <figure class="wide"> <video class="video-gif" controls="" src="https://www.sarasoueidan.com/assets/images/chapter--live-regions/nvda-live-regions-demo.mp4" width="100%"> Sorry, your browser doesn't support embedded videos. </video> </figure> <p>The screen reader announces the contents of the message because I’ve designated the message container as a live region (we’re going to learn how to do that shortly). So now the element is monitored for updates and the screen reader is notified of these updates when they happen. Then, when the button is activated, I inserted the contents of the message into the message container. And when I did, the screen reader was notified and it announced the update to the user.</p> <p>When an update happens in a live region, the screen reader announces that update, and it only announces it once.</p> <p><a href="https://m1.material.io/components/snackbars-toasts.html#snackbars-toasts-usage">Toast messages</a> and other similar status messages are the closest <strong>visual equivalent</strong> of a live region announcement. (Though not all toast messages are a good candidate for live regions. We’ll talk more about this later.)</p> <p>A toast message is used to present <strong>timely information</strong> — including confirmation of actions, statuses, and alerts. By nature, <strong>toast messages are auto-expiring</strong> — they disappear on their own after a few seconds. And once they disappear, they’re gone. The user cannot review the message again.</p> <p>Like toasts, <strong>live region notifications are transient.</strong> <strong>Once an announcement is made, it disappears forever.</strong> They cannot be reviewed, replayed, or revealed later. If the user misses an announcement, they miss it. It’s gone. That is, unless you provide them with a way to review it (like collecting all notifications in a notifications center, for example).</p> <p>Because of their transient nature, live regions have specific and limited use cases and should not be used as an alternative to other more persistent approaches. In fact, if you <em>can</em> use another more persistent approach, you almost definitely should. We’ll talk more about how to use live regions and when <em>not</em> to use live regions later in the chapter.</p> <h2 id="creating-a-live-region" tabindex="-1">Creating a live region</h2> <p>Using ARIA, <strong>almost any element can be designated as a live region</strong>. It doesn’t need to be a structural element; and it doesn’t need to have any implicit semantics by default.</p> <p>You can designate an element as a live region using:</p> <ol> <li>The <code>aria-live</code> attribute.</li> <li>ARIA live region roles.</li> </ol> <p>HTML also provides one native element that has implicit live region semantics: the <code>&lt;output&gt;</code> element. We’re going to talk more about it in another section.</p> <h3 id="1.-using-the-aria-live-attribute" tabindex="-1">1. Using the <code>aria-live</code> attribute</h3> <p><a href="https://www.w3.org/TR/wai-aria-1.2/#aria-live"><code>aria-live</code></a> is the primary attribute used <strong>to designate an element as a live region.</strong> When used on an element, it indicates that this element may be updated, and those updates should be communicated to screen readers.</p> <p>The value of <code>aria-live</code> <strong>describes the types of updates</strong> that can be expected from the region. It accepts three values: <code>assertive</code>, <code>polite</code>, and <code>off</code> (which is equivalent to removing the property altogether).</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token comment">&lt;!-- this div is now a live region! It's as simple as that. --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[ polite | assertive ]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> ...</span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span></code></pre> <p>The value of <code>aria-live</code> you choose will depend on <strong>the type, urgency and priority of the update.</strong></p> <ul> <li>If the update is important enough that it requires the user’s <strong>immediate attention</strong>, <code>assertive</code> will tell the screen reader to <em>immediately</em> notify the user, <strong>interrupting whatever the user’s currently doing.</strong> Assertive notifications are good for when users need to immediately know something and act on it, like when there’s <strong>an error</strong> in submitting information in a form, or something more serious like a <strong>session timeout</strong> or a <strong>security alert</strong>.</li> </ul> <p>Assertive notifications are very disruptive and should be limited to a few use cases where the messages are critical to the user and require their immediate attention. Otherwise, they may disorient users or cause them not to complete their current task.</p> <ul> <li><code>polite</code> on the other hand, is more… polite. It indicates that the screen reader <strong>should wait until the user is idle</strong> (such as when the screen reader has finished reading the current sentence, or when the user pauses typing) before presenting updates to them. Polite regions do not interrupt the user’s current task. They are more suitable for things like success messages, feeds, chat logs, and loading indicators, for example.</li> </ul> <p><code>aria-live=&quot;off&quot;</code> is the assumed default value for all elements. It indicates that updates to the element should not be presented to the user <strong>unless the user is currently focused on that region</strong>.</p> <p>So creating a live region is literally as simple as declaring the <code>aria-live</code> on an element.</p> <p>Here is an example where I have a <code>&lt;div&gt;</code> with no <code>aria-live</code> set on it. When you activate the button, the <code>&lt;div&gt;</code> will get populated with a message via JavaScript; but the screen reader will not announce the update. So the user will not be aware that any content has been added to the <code>&lt;div&gt;</code> at this point.</p> <!-- READ THIS IN VIDEO:

When I add aria-live="assertive" to it, the <div> becomes a live region and is then monitored for updates when they happen. Now when I activate the button again, the screen reader will announce the contents of the message even though focus is not moved to the message. I think that's pretty powerful if you ask me! --> <p>Try adding <code>aria-live=&quot;polite&quot;</code> or <code>aria-live=&quot;assertive&quot;</code> to it and then activate the button again. The screen reader will announce the contents of the message even though focus is not moved to the message:</p> <figure class="wide"> <p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="RwEjmVy" data-user="SaraSoueidan" data-token="b01e1277ca77766ad54b87615074dedb" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/RwEjmVy/b01e1277ca77766ad54b87615074dedb"> Untitled</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> <script async="" src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script> </figure> <p>This is pretty powerful!</p> <p>The live region works even if it is visually-hidden, as long as it is not hidden in a way that removes it from the accessibility tree. (We’ve learned all about choosing an appropriate hiding technique for your content in <a href="https://practical-accessibility.today/chapters/hiding-techniques/">the hiding techniques chapter</a>.)</p> <p>There are some valid use cases for visually-hidden live regions, but the general rule of thumb is that <strong>if the update or message is visible to all users and the conveyed text is equivalent to the visible text (as is the case for most status messages), then you might as well use the same element for screen reader users that you are using for everyone else</strong>, and designate it as a live region so that all users get the same update.</p> <p>For example, consider the dummy email example from the previous section again. To convey the same status message to screen reader users, all you would need to do is designate the message container as a live region using the <code>aria-live</code> property. Error notifications are urgent and require the user’s immediate attention, and you want the user to know that an error has occured as soon as possible. As such, the value of <code>aria-live</code> should be <code>assertive</code>.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>assertive<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span></code></pre> <aside role="note"> <p>At this point it is important to note that you should place the live region container in the DOM as early as possible and <em>then</em> populate it with the contents of the message using JavaScript when the notification needs to be announced. <strong>This ensures that the live region is monitored for updates before they happen.</strong> Otherwise, the update may not be communicated to screen readers. We will learn more about best practices for implementing live regions later in the chapter.</p> </aside> <p>By default, any padding, margin, and border on an element will take up space in the page’s layout even if the element is empty. Since the message container is placed in the DOM before the notification is shown, you will probably want to prevent it from taking up any visual space on the page when it is empty. To do that, you can use the <code>:not(:empty)</code> CSS selector to only apply the visual styles to it when it is <em>not</em> empty (i.e. when the notification is shown).</p> <pre class="language-css"><code class="language-css"><span class="highlight-line"><span class="token selector">[aria-live="assertive"]:not(:empty)</span> <span class="token punctuation">{</span></span><br /><span class="highlight-line"> <span class="token property">padding</span><span class="token punctuation">:</span> .25em 1em<span class="token punctuation">;</span></span><br /><span class="highlight-line"> <span class="token property">background</span><span class="token punctuation">:</span> maroon<span class="token punctuation">;</span></span><br /><span class="highlight-line"> ...</span><br /><span class="highlight-line"><span class="token punctuation">}</span></span></code></pre> <aside role="note"> Because it is a best practice to include live region containers in the DOM as early as possible, I always use this CSS selector to visually “hide” my live regions when they are empty. <p>And yes, yes I know that you can just apply these styles to the notification using a class name that you could add to the container via JavaScript, but why require JS for something so simple that can so easily be accomplished using CSS?</p></aside><p></p> <p>Here is a live demonstration of this implementation:</p> <figure class="wide"> <p class="codepen" data-height="648.68701171875" data-default-tab="html,result" data-slug-hash="rNoJRKw" data-user="SaraSoueidan" data-token="5b5ca2a0db044238fc0f9afee3362619" style="height: 648.68701171875px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/rNoJRKw/5b5ca2a0db044238fc0f9afee3362619"> Live region status message in email web app</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> <figcaption> <p>Fire up a screen reader on <a href="https://codepen.io/pen/debug/rNoJRKw/5b5ca2a0db044238fc0f9afee3362619">the debug version of this demo</a> and then activate the ‘Send’ button.</p> <p>Try removing the <code>:not(:empty)</code> selector from the live region’s ruleset in the to see how it affects the visibility of notification container when it is empty.</p> </figcaption> </figure> <p>A live region does not need to be initially empty.</p> <p>Here’s another example where I have a list and I’m adding items to the list. I’ve designated the list as a assertive live region using <code>aria-live</code>. So now every time an item is added, the screen reader makes an announcement.</p> <figure class="wide"> <p class="codepen" data-height="333.708740234375" data-default-tab="html,result" data-slug-hash="QWxpRRY" data-user="SaraSoueidan" data-token="cc48df344e279aa35cee4ea17f5147b8" style="height: 333.708740234375px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/QWxpRRY/cc48df344e279aa35cee4ea17f5147b8"> #PracticalA11y: Basic live region</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> </figure> <p>This means that you can use live regions to communicate different types of updates to an element, such as when content is added to the element or existing content is modified.</p> <h3 id="live-region-configuration" tabindex="-1">Live region configuration</h3> <p>ARIA provides three <a href="https://www.w3.org/TR/wai-aria-1.2/#attrsliveregions">attributes</a> that enable you to ‘configure’ when the screen reader should make an announcement, and what that announcement should contain:</p> <ul> <li><code>aria-relevant</code>,</li> <li><code>aria-atomic</code>, and</li> <li><code>aria-busy</code>.</li> </ul> <p>These attributes are <em>very</em> useful and would enable you to use live regions to communicate different kinds of content updates when they are needed, but unfortunately current browser and screen reader support is inconsistent, so you can’t rely on them in your projects just yet. But we’re still going to get a quick overview of what they do because it will help you better understand the current limitations with ARIA live regions.</p> <h4 id="aria-relevant%3A-when-should-an-announcement-be-made%3F" tabindex="-1">aria-relevant: when should an announcement be made?</h4> <p><a href="https://www.w3.org/TR/wai-aria-1.2/#aria-relevant">The <code>aria-relevant</code> attribute</a> is used to specify <strong>what type of changes in the live region should trigger an announcement.</strong></p> <p>For example, should the screen reader make an announcement when a node is <em>added</em> to the region? or when a node is <em>removed</em>? or when the text within an element changes? or maybe when any of these updates happen?</p> <p><code>aria-relevant</code> accepts a space-separated list of the following values: <code>additions</code>, <code>removals</code>, <code>text</code>, and a single catch-all value: <code>all</code>.</p> <ul> <li><code>additions</code> will trigger a notification <strong>when a DOM node is added to the region.</strong></li> <li><code>removals</code> will trigger a notification <strong>when a DOM node is removed from the region.</strong></li> <li><code>text</code> will trigger when <strong>text changes happen inside the region</strong>, such as changing a text node inside the region or changing a text alternative for an image inside the region.</li> <li><code>all</code> is a shorthand for all three options.</li> </ul> <p>The default value is <code>additions text</code>, which means that a live region will trigger an announcement when content is added or text is changed within the region.</p> <p>The <code>removals</code> and <code>all</code> values should be used sparingly. Screen reader users only need to be informed of content removal when its removal represents an important change, such as when a user is removed from the list of active users in a chat room, for example.</p> <h4 id="aria-atomic%3A-what-is-contained-in-an-announcement%3F" tabindex="-1">aria-atomic: what is contained in an announcement?</h4> <p><a href="https://www.w3.org/TR/wai-aria-1.2/#aria-atomic">The <code>aria-atomic</code> attribute</a> determines what is contained in the announcement. It indicates whether the screen reader should present all or only parts of the changed element based on the change notifications defined by the <code>aria-relevant</code> attribute.</p> <p>For example, if a piece of text changes inside an element, should the screen reader announce only the changed text? or the entire contents of the live region? If text is <em>added</em> to a live region, should only the newly added text be announced? or should the entire region’s content be announced every time?</p> <p><code>aria-atomic</code> accepts two values: <code>true</code>, and <code>false</code>.</p> <ul> <li>When <code>aria-atomic</code> is <code>false</code>, a screen reader should only announce the parts of the element that have changed. <strong>This is the default value.</strong></li> <li>When <code>aria-atomic</code> is <code>true</code>, the screen reader should announce the entire contents of the live region when a change happens inside of it. It doesn’t matter what has changed. It’s going to read everything — the entire content of the live region, plus the region’s accessible name, if it has one.</li> </ul> <p><code>aria-atomic=&quot;true&quot;</code> is useful for when a part of the region changes but you want the entire content to be read because otherwise the updated content may not make much sense on its own. A practical example is a “Now Playing” indicator.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Now Playing:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>[ movie/soundtrack title ]<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></span></code></pre> <p>If a playlist of movies or soundtracks is playing while the user performs other tasks on the page, and the name of the soundtrack that is currently playing changes, you can utilize live regions to announce that a new soundtrack is playing.</p> <p>When the soundtrack changes, the only part of the indicator that gets updated is the soundtrack’s name. But you want the entire sentence to be announced so that the user gets the context they need. You can do that by designating the indicator as an atomic live region (using <code>aria-atomic=&quot;true&quot;</code>):</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span> <span class="token attr-name">aria-atomic</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Now Playing:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>[ movie/soundtrack title ]<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></span></code></pre> <p>Now every time the title of the soundtrack or movie changes, the screen reader should announce “Now playing” followed by the name of the soundtrack.</p> <p>Here is a live demo:</p> <figure class="wide"> <p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="poqOVRX" data-user="SaraSoueidan" data-token="971da72a6c94e0bd5352808818565dd8" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/poqOVRX/971da72a6c94e0bd5352808818565dd8"> Untitled</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> <figcaption> <p>Start a screen reader and try out <a href="https://codepen.io/pen/debug/poqOVRX/971da72a6c94e0bd5352808818565dd8">the debug version of the playing indicator</a></p> </figcaption> </figure> <h4 id="aria-busy%3A-please-wait-until-the-changes-are-complete" tabindex="-1">aria-busy: please wait until the changes are complete</h4> <p>The <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-busy"><code>aria-busy</code> attribute</a> is used to indicate that an element (typically an entire section on the page) is undergoing changes (such as a section loading new content), and that screen readers should therefore <strong>wait until the changes are complete before exposing the content to the user</strong>.</p> <p>By default, all elements have an <code>aria-busy</code> value of <code>false</code>. Meaning that they are <em>not</em> undergoing changes and screen readers can, therefore, expose their content when the user navigates to them.</p> <p>To use <code>aria-busy</code>, you would set it to <code>true</code> on an element while the element is undergoing changes, and then flip its value to <code>false</code> when the changes are complete and ready to be exposed or announced to the user.</p> <p><code>aria-busy</code> can be used on any element that is undergoing changes, even if that element is not a live region.</p> <p>If you use <code>aria-busy</code> on a live region, the contents of the live region will be announced after <code>aria-busy</code> is set to <code>false</code>. If multiple changes have been made to the element while it was busy, they are announced as a single unit of speech when <code>aria-busy</code> is turned off.</p> <p>‘<a href="https://www.nngroup.com/articles/skeleton-screens/">Skeleton screens</a>’ in Single Page Applications (SPA) are a practical use case for the <code>aria-busy</code> attribute.</p> <p>A skeleton screen is a specific type of loading indicator that is shown in lieu of the content of a section being loaded until the content of that section loads. They often provide a wireframe-like visual that mimics the layout of the page and helps users build a mental model of what will be on the page when the content loads.</p> <figure class="wide"> <picture><source type="image/webp" srcset="https://www.sarasoueidan.com/assets/images/youtube-skeleton-600w.webp 600w, https://www.sarasoueidan.com/assets/images/youtube-skeleton-900w.webp 900w, https://www.sarasoueidan.com/assets/images/youtube-skeleton-1500w.webp 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><source type="image/jpeg" srcset="https://www.sarasoueidan.com/assets/images/youtube-skeleton-600w.jpeg 600w, https://www.sarasoueidan.com/assets/images/youtube-skeleton-900w.jpeg 900w, https://www.sarasoueidan.com/assets/images/youtube-skeleton-1500w.jpeg 1500w" sizes="(max-width: 768px) 100vw, 50vw" /><img alt="Screenshot of the Youtube homepage showing a skeleton screen, where grey rectangular boxes visually represent videos and video descriptions." class="undefined" loading="lazy" decoding="async" src="https://www.sarasoueidan.com/assets/images/youtube-skeleton-600w.jpeg" width="1500" height="937" /></picture> </figure> <p><code>aria-busy</code> can be used to tell screen readers to ignore the section that is currently loading content until the content finishes loading. In that sense, it has a similar effect to <code>aria-hidden</code> — it ‘hides’ the contents of a busy region while it is undergoing changes.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token comment">&lt;!-- This section is updating... --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">aria-busy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> .. </span><br /><span class="highlight-line"> <span class="token comment">&lt;!-- more content is loading --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></span></code></pre> <p>Since the busy section is effectively hidden from screen reader users, you will want to communicate the state of the loading content to screen reader users.</p> <p>You can do that by using a separate, visually-hidden live region. Using this region, you can communicate to the user that a screen has started loading, and then let them know when the loading is complete. So, when the content is loading, your markup would at a certain moment look like this:</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>visually-hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Loading content...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">aria-busy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> .. </span><br /><span class="highlight-line"> <span class="token comment">&lt;!-- more content is loading --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></span></code></pre> <p>and then when the content is loaded, flip the value of <code>aria-busy</code> to <code>false</code>, and update the content of the live region:</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>visually-hidden<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Content loaded.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">aria-busy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> .. </span><br /><span class="highlight-line"> <span class="token comment">&lt;!-- more content is loading --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></span></code></pre> <aside role="note">This is an example of when a live region can be used exclusively for notifying screen reader users, but doesn’t need to be rendered visually because there is an alternative visual indicator for sighted users (the skeleton screen, in our case). So you can think of the live region like a text alternative for the skeleton screen in this case.</aside> <p>Unfortunately, because <code>aria-busy</code> is currently not well-supported across screen reader and browser pairings, most screen readers (except JAWS) will read the contents of the busy region even before it’s done loading, which would result in a sub-optimal experience.</p> <p>You currently need to work your way around that by hiding the busy region using <code>aria-hidden</code>, and un-hiding it when its contents are done loading.</p> <p>For a detailed writeup about implementing accessible skeleton screens, check out Adrian Roselli’s article <a href="https://adrianroselli.com/2020/11/more-accessible-skeletons.html">“More Accessible Skeletons”</a>. Adrian provides a solution that doesn’t even require you to use live regions at all, and his article includes <a href="https://codepen.io/aardrian/pen/yLOoOdY">a live demo</a> that you can tinker with and try for yourself.</p> <h4 id="summary-and-support-landscape" tabindex="-1">Summary and support landscape</h4> <table class="wide"> <caption>Properties for configuring live region announcements</caption> <thead> <tr> <th scope="col">Value</th> <th scope="col">Description</th> </tr> </thead> <tbody> <tr> <th class="value-name" scope="row"><code>aria-atomic</code></th> <td class="value-description"> <p><em>What is announced? When you update a live region, should it read all the content again or just the added content?</em></p> <p>If <code>true</code>: Announce the entire content of the live region, including its label, if present.</p> <p>If <code>false</code>: announce only the changed content.</p> </td> </tr> <tr> <th class="value-name" scope="row"><code>aria-relevant</code></th> <td class="value-description"> <p><em>When is an announcement made? What types of changes to a live region should trigger the announcement? additions? removals? or all?</em></p> <p>If <code>additions</code>: Trigger an announcement when new elements are added to the accessibility tree of the live region.</p> <p>If <code>text</code>: Trigger an announcement when text content or a text alternative is added to any descendant in the accessibility tree of the live region.</p> <p>If <code>removals</code>: Trigger an announcement when an element, text, or text alternative is removed from the accessibility tree of the live region.</p> <p>If <code>additions text (default)</code>: Equivalent to the combination of <code>additions</code> and <code>text</code>.</p> <p>If <code>all</code>: Equivalent to the combination of <code>additions removals text</code>.</p> </td> </tr> <tr> <th class="value-name" scope="row"><code>aria-busy</code></th> <td class="value-description">Indicates that an entire section on the page is undergoing changes (such as a section loading new content), and you're telling screen readers to <strong>wait until the changes are complete before notifying the user</strong> <p>If <code>true</code>: The element is being updated.</p> <p>If <code>false</code>: There are no expected updates for the element.</p> </td> </tr> </tbody> </table> <p>As we mentioned earlier, <strong>support for the <code>aria-relevant</code>, <code>aria-atomic</code>, and <code>aria-busy</code> attributes is currently inconsistent across browsers and screen reader pairings.</strong></p> <p>Paul J. Adam has created <a href="https://pauljadam.com/demos/aria-atomic-relevant.html">a test page that includes test cases for <code>aria-atomic</code> and <code>aria-relevant</code></a> when used on live regions, and has documented support gaps across platforms and screen readers.</p> <p>So, unfortunately, you can’t rely on these properties in your projects just yet. If you do, many of your content updates may be announced in ways that you did not intend them to be announced, which could result in a sub-optimal user experience.</p> <h3 id="2.-using-live-region-roles" tabindex="-1">2. Using live region roles</h3> <p>When you use <code>aria-live</code> to create a live region, the element’s implicit semantics (if it has any) are retained. This means that you can use the appropriate element to represent the component you’re creating, and if the component is getting updated you can then designate it as a live region with the <code>aria-live</code> attribute.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token comment">&lt;!-- this list will be treated like any list on the page would be; since it is also designated as being live, any changes that happen to it should be communicated to screen readers and announced to the user --></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">aria-live</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>polite<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>My list semantics are important.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>But I want you to know when new list items are added.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></span></code></pre> <p>But what if you’re creating a notification or status message that has no semantic HTML element to represent it? For example, there are no semantic elements to represent (and distinguish between) different types of notifications (such as an alert notification or a status message, for example).</p> <p>While it is fine to use a <code>&lt;div aria-live=&quot;&quot;&gt;</code> for these notifications, it would be ideal if we exposed the nature or type of a notification to the user using appropriate semantics.</p> <p>ARIA provides <a href="https://www.w3.org/TR/wai-aria-1.2/#liveregion_roles">five live regions roles</a> that semantically represent five different types of updates:</p> <ul> <li><strong>The <code>alert</code> role:</strong> represents a live region with important, and usually time-sensitive information, such as error notifications.</li> <li><strong>The <code>status</code> role:</strong> represents a live region whose content is advisory information for the user but is not important enough to justify an alert, often but not necessarily presented as a status bar (such as a status or success message).</li> <li><strong>The <code>log</code> role:</strong> represents a live region where new information is added <strong>in meaningful order</strong>, and old information may disappear. Examples of logs are chat logs, messaging history, a game log, or an error log. In contrast to other live regions, <strong>in this role there is a relationship between the arrival of new items in the log and the reading order.</strong> The log contains a meaningful sequence and new information is added only to the end of the log, not at arbitrary points.</li> <li><strong>The <code>marquee</code> role:</strong> represents a live region where non-essential information changes frequently, such as stock tickers. The primary difference between a marquee and a log is that logs usually have a meaningful order or sequence of important content changes.</li> <li><strong>The <code>timer</code> role:</strong> represents a live region containing a numerical counter which indicates an amount of elapsed time from a start point, or the time remaining until an end point.</li> </ul> <p>Live region roles are <strong>pre-configured</strong>. They come with <em>implicit</em> <code>aria-live</code> and <code>aria-atomic</code> values.</p> <!-- - Elements with the role alert have an implicit assertive aria-live value. They also have an implicit aria-atomic value of true.

  • Elements with the role status have an implicit aria-live="polite" and an implicit aria-atomic value of true.

--> <table> <caption>ARIA live region roles and their implicit <code>aria-live</code> and <code>aria-atomic</code> mappings</caption> <thead> <tr> <th scope="col">Role</th> <th scope="col"><code>aria-live</code> value</th> <th scope="col"><code>aria-atomic</code> value</th> </tr> </thead> <tbody> <tr> <th class="value-name" scope="row"><code>alert</code></th> <td class="value-description"><code>assertive</code></td> <td class="value-description"><code>true</code></td> </tr> <tr> <th class="value-name" scope="row"><code>status</code></th> <td class="value-description"><code>polite</code></td> <td class="value-description"><code>true</code></td> </tr> <tr> <th class="value-name" scope="row"><code>log</code></th> <td class="value-description"><code>polite</code></td> </tr> <tr> <th class="value-name" scope="row"><code>marquee</code></th> <td class="value-description"><code>off</code></td> </tr> <tr> <th class="value-name" scope="row"><code>timer</code></th> <td class="value-description"><code>off</code></td> </tr> </tbody> </table> <p><code>alert</code> and <code>status</code> are the most commonly used live regions roles and have generally good support. The others have specialized uses and have <strong>poor or no support</strong>, and <code>marquee</code> and <code>timer</code> are even <a href="https://github.com/w3c/aria/issues/1104">in danger of being deprecated and removed from the ARIA specification</a>.</p> <!-- <aside role="note">

If you want to use the other three live region roles, you'd need to work your way around the lack of support.

For example, the log live region role was made for UI components like chat interfaces. By using the log role on the chat container, the user can be notified of new messages as they appear in the chat while they are composing a new message.

The log role is a non-atomic, polite live region. So, when a new message is inserted to the chat, only that message should be announced. You don't want the screen reader to announce the entire content of the chat every time a new message arrives. But because the log role is not fully supported, you may end up with a live container that reads the entire chat history every time a new message arrives.

One way you can work around the lack of support is to use a separate, visually-hidden (polite) live region. Then when an incoming message arrives, you insert a copy of that message into the live region so that only this message is announced. You will want to do that for every incoming message, inserting them one by one into the visually-hidden live region, and emptying the live region between insertions. This could ensure maximum compatibility on different platforms, and it would also ensure the chat messages are announced as they are intended.

It is important to note at this point that while chat interfaces do update asynchronously, they don't always need to be implemented as live regions. Unless the chat is the main interface on the page, it probably shouldn't be a live region. </aside> --> <h4 id="difference-between-using-aria-live-and-live-region-roles" tabindex="-1">Difference between using <code>aria-live</code> and live region roles</h4> <p>The primary difference between using live region roles and using <code>aria-live</code> on its own is that <strong>live region roles have semantic meaning.</strong> They add explicit <em>semantics</em> to an element (<q>This is an alert</q>, <q>This is a status message</q>, etc.), so some screen readers may announce “alert” before announcing the content of the message.</p> <p>For example, here is the dummy email app example again. Instead of using <code>aria-live=&quot;assertive&quot;</code> on the notification container, I’m using <code>role=&quot;alert</code>. Here’s a video comparing how NVDA announces the notification, first when it is designated as a live region using <code>aria-live=&quot;assertive&quot;</code>, and the when it is designated as a live region using <code>role=&quot;alert&quot;</code>.</p> <figure class="wide"> <video class="video-gif" controls="" src="https://www.sarasoueidan.com/assets/images/chapter--live-regions/nvda-live-regions-demo-2.mp4" width="100%"> Sorry, your browser doesn't support embedded videos. </video> <figcaption> <p>NVDA announces the word “Alert” before announcing the content of the notification when <code>role=&quot;alert&quot;</code> is used. You can try it for yourself in <a href="https://cdpn.io/pen/debug/zYyWzmd/5f0c8bc535640bab3cea6bd22f61d5a2">the debug version of the demo using the role attribute</a>. </p></figcaption><p></p> </figure> <p>Here is another example that implements a form success message using <code>role=&quot;status&quot;</code>:</p> <figure class="wide"> <p class="codepen" data-height="482.22021484375" data-default-tab="html,result" data-slug-hash="YzdOYRL" data-user="SaraSoueidan" data-token="270940e995dd0db53a156fd0637d22e0" style="height: 482.22021484375px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/YzdOYRL/270940e995dd0db53a156fd0637d22e0"> #PracticalA11y: role status success message</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> </figure> <p>Another advantage to using a live region role over <code>aria-live</code> is that <strong>live region roles accept an accessible name.</strong></p> <p>If you use <code>aria-live</code> to create a live region, the implicit semantics of the element you’re using it on will determine whether or not it can have an accessible name. As we learned in <a href="https://practical-accessibility.today/chapters/accName/#not-all-elements-can-have-a-name">the accessible names and descriptions chapter</a>, some elements are name-prohibited. For instance, a <code>&lt;div&gt;</code> will not consistently expose an accessible name unless you give it a meaningful role. ARIA live region roles provide meaningful roles to the elements they are used on and can therefore accept an accessible name.</p> <p>When a live region has an accessible name, screen readers include the name of the region in the announcement.</p> <figure class="wide"> <p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="qBLMxPM" data-user="SaraSoueidan" data-token="20ae0def0cbc9ec524d376433ae21d37" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/qBLMxPM/20ae0def0cbc9ec524d376433ae21d37"> #PracticalA11y: shopping cart</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> <figcaption> <p>In this example I have a polite live region that contains the number of items in the user’s shopping cart. When the ‘Add to cart’ button is activated, the number of items is updated and the screen reader announces that number. But anouncing the number of items alone doesn’t provide the user with the same context that sighted users get when the shopping cart is visually updated. Ideally, you’d want the screen reader to announce “Shopping cart, 5 items”.</p> <p>Using <code>aria-labelledby</code>, you can provide an accessible name to the live region (namely: “Shopping Cart”). So now when the number of items is announced, the screen reader announces ‘Shopping cart’ before announcing the number of items it contains.</p> <p>You can try the live example out for yourself in <a href="https://codepen.io/pen/debug/qBLMxPM/20ae0def0cbc9ec524d376433ae21d37">the debug version of the shopping cart example</a>.</p> </figcaption> </figure> <p>Providing an accessible name to a live region is useful for when you may have multiple updating regions on the page and you want to communicate which region the updates are coming from. A region’s name thus provides the necessary context for each announcement.</p> <h3 id="3.-using-the-html-output-element" tabindex="-1">3. Using the HTML <code>output</code> element</h3> <p>HTML provides one native live region element: <code>&lt;output&gt;</code>.</p> <p><a href="https://html.spec.whatwg.org/multipage/form-elements.html#the-output-element">By definition</a>, <code>&lt;output&gt;</code> represents an element into which you can inject the results of a calculation <strong>or the outcome of a user action.</strong> The second part of the definition can be interpreted to mean that the <code>&lt;output&gt;</code> element can be used to display a feedback message as a result of user interaction (like a toast or status message!).</p> <p>The <code>&lt;output&gt;</code> element has implicit live region semantics. It maps to the ARIA <code>status</code> role, which means that it represents a polite live region.</p> <p><code>&lt;output&gt;</code> is also a <a href="https://html.spec.whatwg.org/multipage/forms.html#category-label">labelable element</a>, which means that you can give it an accessible name using the <code>&lt;label&gt;</code> element.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[ outputID ]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>..<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[ outputID ]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> .. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token comment">&lt;!-- or --></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[ outputID ]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> ..</span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[ outputID ]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span></span></code></pre> <p>A practical use case for the <code>&lt;output&gt;</code> element is using it to represent the total price of products in a cart on an e-commerce website.</p> <pre class="language-html"><code class="language-html"><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>result<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Your total is:<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>result<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token comment">&lt;!-- or --></span></span><br /><span class="highlight-line"></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>result<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"> Your total is:</span><br /><span class="highlight-line"> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>result<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span></span><br /><span class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span></span></code></pre> <p>When the user updates the number of items in their cart, the total price is updated to reflect the new total price. Wrapping the price in an <code>&lt;output&gt;</code> element allows it to be announced by the screen reader when it is updated.</p> <p>Here is a dummy example where the total price is updated based on how many items are chosen in the select dropdown:</p> <figure class="wide"> <p class="codepen" data-height="432" data-default-tab="html,result" data-slug-hash="QWxwBML" data-user="SaraSoueidan" data-token="47ad4c41a8d8bb83b9bef7d5d235d483" style="height: 432px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;"> <span>See the Pen <a href="https://codepen.io/SaraSoueidan/pen/QWxwBML/47ad4c41a8d8bb83b9bef7d5d235d483"> #PracticalA11y: The &lt;output&gt; live region element</a> by Sara Soueidan (<a href="https://codepen.io/SaraSoueidan">@SaraSoueidan</a>) on <a href="https://codepen.io/">CodePen</a>.</span> </p> </figure> <p>You have probably also noticed that VO with Safari announces the initial total value before it announces the updated total value every time it makes an announcement.</p> <p>The <code>&lt;output&gt;</code> element is currently not consistently announced across browser and screen reader pairings. And not all screen readers announce the accessible name of the <code>&lt;output&gt;</code> when its content is updated. For example, VoiceOver with Safari announces the content of the <code>&lt;output&gt;</code> element in the example above but it does not announce its accessible name. NVDA with Firefox does not announce the accessible name either. Whereas paired with Chrome, VoiceOver announces the contents of <code>&lt;output&gt;</code> with its accessible name as it is intended.</p> <p>There are also other quirks and some inconsistencies in the way <code>&lt;output&gt;</code> is currently announced across browser and screen reader pairings. Accessibility engineer Scott O’Hara has written <a href="https://www.scottohara.me/blog/2019/07/10/the-output-element.html">a great article about the <code>&lt;output&gt;</code> element</a> that I recommend reading if you want to learn more details about <code>&lt;output&gt;</code> and its quirks. Scott shares the current state of support, as well as suggestions for working around some of the support gaps.</p> <!-- such as explicitly assigning the role="status" to the <output> to work around the lack of support in Firefox and Internet Explorer 11: --> <!-- ``html <output role="status"></output> `` --> <h2 id="summary-and-outro" tabindex="-1">Summary and outro</h2> <p>So, to quickly sum up:</p> <ul> <li>ARIA live regions are a specific type of notification system primarily surfaced for screen reader users.</li> <li>You can create a live region using the <code>aria-live</code> attribute. The value of the attribute depends on the type and urgency of the updates you’re communicating.</li> <li>The <code>aria-relevant</code>, <code>aria-atomic</code>, and <code>aria-busy</code> attributes allow you to configure when an announcement should be made and what the announcement should contain. But support for these attributes is currently poor.</li> <li>ARIA provides five roles that represent five different types of updates. Of these five roles, <code>alert</code> and <code>status</code> have the best support and can be used to represent status messages in web applications.</li> <li>The <code>&lt;output&gt;</code> element is currently the only native HTML live region. The <code>&lt;output&gt;</code> element has a few quirks and some support gaps that, depending on your use case, you may be able to work around today.</li> </ul> <p>As you might imagine, the current state of support for live region features and properties limits your uses of live regions quite a bit. Furthermore, the inherent behavior of live regions also makes them unsuitable for certain types of updates. We’re going to elaborate more on this in the second part of this chapter.</p> <p>Fortunately, for many (if not most!) common UI patterns, there’s often a more robust way to make users aware of content updates when they happen. And for the few instances when you do need to use live regions, you can make them work by following a few implementation best practices. We will discuss all of that in more detail in <a href="https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-2">the second part</a> of this chapter.</p> <br /> <aside role="note">Many thanks to <strong>James Edwards</strong> (<a href="https://twitter.com/siblingpastry">@siblingpastry</a>) for reviewing this chapter.</aside>

Jump to
Projectsbrowse
Peoplebrowse
Companiesbrowse
Saved
Editor
Autosaves as you type