diff --git a/src/_data/authors.json b/src/_data/authors.json index e90178b2f..531729e72 100644 --- a/src/_data/authors.json +++ b/src/_data/authors.json @@ -229,11 +229,18 @@ "biography": "Founder of MadHackerHaus and Rolled Up Sleeves, LLC. Advocate for accessibility in developing the internet and mobile technology." }, { - "name": "Rachel R. Vasquez", - "first": "Rachel", - "website": "http://rachievee.com", - "photo": "https://avatars0.githubusercontent.com/u/10246844?s=460&v=4", - "biography": "Senior WordPress Developer." + "name": "Nat Tarnoff", + "first": "Nat", + "website": "http://tarnoff.info/", + "photo": "https://pbs.twimg.com/profile_images/855580021951537152/bS14U2d5_400x400.jpg", + "biography": "Founder of MadHackerHaus and Rolled Up Sleeves, LLC. Advocate for accessibility in developing the internet and mobile technology." + }, + { + "name": "Paul McFedries", + "first": "Paul", + "website": "https://paulmcfedries.com", + "photo": "https://avatars.githubusercontent.com/u/7156439?s=200&v=4", + "biography": "Author of more than 100 technical books, including Web Design Playground, Web Coding and Development All-in-One For Dummies, and HTML, CSS, and JavaScript All-in-One For Dummies." }, { "name": "Rian Rietveld", diff --git a/src/img/posts/ajax-with-aria-live/aria-live-region-with-voiceover-text.png b/src/img/posts/ajax-with-aria-live/aria-live-region-with-voiceover-text.png new file mode 100644 index 000000000..1a5ed8ebf Binary files /dev/null and b/src/img/posts/ajax-with-aria-live/aria-live-region-with-voiceover-text.png differ diff --git a/src/posts/ajax-with-aria-live.md b/src/posts/ajax-with-aria-live.md new file mode 100644 index 000000000..91dc7d1e8 --- /dev/null +++ b/src/posts/ajax-with-aria-live.md @@ -0,0 +1,120 @@ +--- +title: Using Ajax with ARIA live regions +description: How to set up ARIA live regions so that assistive technologies can announce when dynamic content is added to the page via an Ajax call. +category: How-to +author: Paul McFedries +date: 2023-03-29 +tags: + - howto +--- + +Many web pages avoid page reloads by using Ajax calls to retrieve dynamic content from a server and display that content on the page. Sighted users can see the new content, but assistive technologies cannot. + +To ensure all your readers can view your dynamic content, you need to configure the region where that content appears as an ARIA live region. This article tells you everything you need to know. + +## The problem: assistive technology doesn't announce dynamic content + +When a person using assistive technology (AT) such as a screen reader first visits a web page, the AT parses the page and creates an accessibility tree for the page structure and content. By default, the AT only updates that accessibility tree on a page reload. This means that if your page has a script that uses Ajax to retrieve new content from a server and display that content on the page, the AT has no default mechanism for announcing the new content. + +## The solution: live regions + +Fortunately, there are ways to work around this limitation. For example, one way to enable an AT to announce dynamic page content is to use the `role` attribute to set up an element as a *live region*. This is a page region that the AT monitors for changes and announces any new or changed content to the user. By default, any of the following `role` attribute values specify an element as a live region: `alert`, `log`, `marquee`, `status`, or `timer`. + +However, not every region with dynamic content falls neatly into one of these roles. When you have a `div` or other element that doesn’t fit any of the live-region roles, you can still configure the element as a live region by using the `aria-live` attribute. + +## Understanding the `aria-live` values + +The `aria-live` attribute can take one of the following three values: + +- `aria-live="polite"` Configures the element as a live region, but only announces new or changed dynamic content when the user is idle. +- `aria-live="assertive"` Configures the element as a live region, and will interrupt whatever task the user is currently performing to announce new or changed dynamic content. +- `aria-live="off"` Configures the element to not act as a live region. This is the default for all elements, but can be useful if you want to override a `role` attribute that has an implicit `aria-live` value. + +**Note:** It’s best to stick with `aria-live="polite"` because it’s the least intrusive for the user. Only use `aria-live="assertive"` if the dynamic content you're adding is extremely important. + +Here’s an example: + +```html +
+
+``` +The `div` element is empty when the page loads. Now suppose that via an Ajax call, the above `div` element gets populated with some dynamic content: +```html +
+ Your changes have been saved. +
+``` +Thanks to the inclusion of the `aria-live="polite"` attribute, a screen reader or similar assistive technology will notice the new content and announce it to the user. + +**Note:** When you enable a live region on an element using `aria-live`, that live region also includes all of the element’s descendants. + +## Example: updating a region with content from a remote API + +A web page uses a button to retrieve a “Dad” joke from an application programming interface (API) provided by icanhazdadjoke.com. Here's the HTML: +```html +

Dad Jokes

+ +
+``` +Note, in particular, the addition of the `aria-live="polite"` attribute to the `div` element. + +The dynamic content comes via an Ajax call that’s triggered when the button is clicked: +```javascript +async function getJoke() { + try { + const response = await fetch('https://icanhazdadjoke.com/', { + headers: { + Accept: 'application/json' + } + }); + + if (!response.ok) { + throw new Error('Request failed.'); + } + + const data = await response.json(); + const output = document.querySelector('#show-joke'); + output.innerHTML = data.joke; + + } catch (error) { + console.error(error); + } +} + +const btn = document.querySelector('#get-joke'); +btn.addEventListener('click', () => { + getJoke(); +}); +``` + +The example web page with the focus on the Get a Dad Joke button. The region below the button displays a joke, which is the dynamic content retrieved via an Ajax call to the API. At the bottom of the screen, a Voiceover subtitle box displays the same joke. + +## Fine-tuning ARIA live regions + +To make your ARIA live regions work the way you want, there are two other attributes you can use: + +- `aria-atomic="true|false"` Determines how much of the changed live region the user's assistive technology announces to the user. Setting `aria-atomic="false"` tells the AT to announce only what has changed within the region. Setting `aria-atomic="true"` tells the AT to announce the entire live region +- `aria-relevant="keyword(s)"` A space-separated list of one or more keywords that define the types of changes you want the user's assistive technology to announce: + - `additions` The AT announces when element nodes are added to the live region. + - `text` The AT announces when text is added to the live region. + - `removals` The AT announces when element nodes are removed from the live region. + - `all` The AT announces node additions, text additions, and node removals. That is, setting `aria-relevant: all` is the same as setting `aria-relevant: additions text removals`. + +**Note:** The default value for `aria-relevant` is `additions text`. + +## Understanding the connection between ARIA roles and live regions + +As mentioned earlier, some ARIA roles automatically configure an element as a live region, so those elements don’t require the `aria-live` attribute. The following table shows the `role` attribute values that automatically create live regions and shows the implicit `aria-live` and `aria-atomic` values associated with each role. + +| `role=` Value | Use Cases | Implicit `aria-live` Value | Implicit `aria-atomic` Value | +| ------------- | ------------- | ----------- | ----------- | +| `alert` | Errors and warnings | `aria-live="assertive"` | `aria-atomic="true"` | +| `log` | Error logs, chat logs, game logs | `aria-live="polite"` | `aria-atomic="false"` | +| `marquee` | Stock tickers, news crawlers | `aria-live="off"` | N/A | +| `status` | Status updates | `aria-live="polite"` | `aria-atomic="true"` | +| `timer` | Countdown timers, stopwatches | `aria-live="off"` | N/A | + +## Summary + +Bringing in dynamic content using Ajax calls to a server is a common pattern in today’s web. Dynamic content can make a page feel more lively and useful, but only if every page visitor has access to that content. Fortunately, it takes but a few moments of your time to turn a dynamic-content element into a live region that’s accessible to everyone. \ No newline at end of file