Accessibility Quick Wins: Error messages with aria-live

Photo by Yomex Owo on Unsplash

A very common use case concerning accessibility is to announce dynamic content changes (which happen without full page reload) to assistive technologies (ATs). Some examples include announcing remaining time based on a javascript clock; dynamic error messages which appear based on input validation; sports scores which update periodically, search results updated dynamically without reloading the page, etc. Well, aria-live to the rescue.

aria-live is a way to apprise ATs of any dynamic changes that need to be announced to the user. It takes 3 values: off, polite, assertive.

  • off is as good as not specifying aria-live, probably useful when you want to turn off live updates for an element from javascript.
  • polite hints that ATs should announce the change when the user is idle (which means the announcement isn’t as important to announce it right away, disturbing user’s ongoing work),
  • assertive hints that the updates are important and should be announced right away.

Note: implementations might vary on how screen readers handle this.

Let’s see aria-live in action using a Login Form:

The codesandbox contains a (contrived) use case example of aria-live paired with aria-atomic to announce the full content of the error (You have an error: followed by the actual error ) when the error message changes. You can turn aria-atomic to false to only announce the error message and not the full content.

Note: If you haven’t worked with a screen reader before, ChromeVox is a nice place to start, you can install the ChromeVox extension in chrome.

aria-live caveats:

  • It is suggested that the DOM element with aria-live is present in the DOM on page load for the ATs to pick it up and monitor for changes. aria-live only comes into picture once the contents actually change, not on the initial load. This means that dynamically adding an element with aria-live will have no effect for the first time when it is added.
  • Usually it is a good idea to pair aria-atomic with aria-live. aria-atomic would make sure that all the content within the aria-live element would be read on change, otherwise you might find yourself in situations where the aria-live announcement doesn’t make sense (For example , if you are using aria-live to announce every minute when a javascript clock changes, it would make sense to announce the complete time instead of only the minute that has changed. aria-atomic would help you do that. Without aria-atomic only the node that has changed within the parent node (with aria-live) is announced (You can experiment with this in the codesandbox by turning aria-atomic to false)
  • if you are showing the same error message when the same action happens again, it might help avoid some bugs if you just clear the error message between two invocations of the error. For example, in a login form, if the user enters wrong credentials for the first time, you show an error message, now if they enter invalid credentials again and you haven’t cleared the error message, although there is still an error, this new state might not be announced by ATs because the aria-live DOM content hasn’t changed. So, it is advised to clear your content between multiple invocations of errors which need to be announced using aria-live. ( This depends on whether or not you are actually updating the DOM with the same error message, in frameworks like React, since the error message hasn’t changed, so DOM won’t be updated and the aria-live won’t be announced. If you do it using innerHTML in vanilla js (which we are doing in the codesandbox example) then you are updating the DOM every time so the changes would be announced as usual and you do not need to clear it.

A better example for aria-atomic can be found here:

Further Reading:

there is a related aria-relevant attribute, which hints to the screenreader what kind of changes to announce (additions, removals, text, all) , but at the time of writing this article, it doesn’t seem like a good idea to use it. You can play with it in the attached codesandbox, try to put aria-relevant=”removals” and observe that it doesn’t announce the additions to error message, but announces the removal if you clear the error message.

Specific aria-roles:
MDN mentions specific aria-roles for multiple use cases of dynamic content instead of using aria-live. These roles include log, status (useful for announcing when the status of something changes, for example, file uplaod status), alert (useful for the error message use case we discuss in this post), etc.