Skip to main content

Screen Reader Messaging

Introduction

Sometimes, a web page may need to provide a message to assistive technologies that an event happened. For example, if a data table was resorted based on a column, a screen reader should be informed the table was successfully resorted. In general, any dynamic action that shows visual evidence may need to provide confirmation.

The Screen Reader Messaging (SRM) library provides a straightforward means of passing a message to screen readers and other assistive technologies via a visually hidden live region using the two ARIA attributes aria-live and aria-atomic.

This JavaScript library and supporting information are an open source project on GitHub released under the Mozilla Public License Version 2.0.

The SRM library is designed for easy, straightforward deployment. One needs to only include the small script file:

<script src="dist/sr-messaging.js"></script>

After a short (<1s) delay after page load for the browser's accessibility tree to recognize the added ARIA live region, the messaging service is ready for use. Whenever a message needs to be sent to a screen reader, just grab the SRM messenger object and use the say() method to deliver the message:

let srm = ScreenReaderMessenger.getMessenger();
srm.say('Hello World!');

The SRM library uses the singleton pattern, meaning there is only screen reader messaging service available at any time. Each time you call getMessenger(), you will receive the same SRM object.

The following demonstrates the screen reader messaging utility. Clicking the button returns the current seconds in the current time. This message is conveyed in three ways:

The overall code for implementing the example is straightforward. More lines were needed to implement the timestamp formatting for the debug log! If the debugging feedback was not included, the code could be simplified to the following vanilla HTML and JavaScript:

<head>
	...
	<script src="dist/sr-messaging.js"></script>
</head>
<body>
	...
	<script>
		window.addEventListener('load', function(event) {
			document.getElementById('speak-trigger').addEventListener('click', function(evt) {
				let d = new Date();
				ScreenReaderMessenger.getMessenger().say('Seconds are ' + d.getSeconds();
			});
		});
	</script>
</body>

Note how you can chain the getMessenger() and say() methods if so desired.

The SRM library functions through the coordination of a DIV that is an ARIA live region and the ScreenReaderMessenger object that coordinates updating and timing of the message.

Creating an ARIA Live Region

Creating an ARIA Live Region Anchor Link

Once the page is loaded, the SRM appends a DIV element to the DOM. This DIV element will temporarily contain the text of the messages. Importantly, this DIV is styled so that it is shown to only screen reader users. If the DIV was hidden using techniques like display:none, messaging would not work.

This DIV's "invisible" styling is similar to other common CSS for invisible content for screen reader users. As it is positioned absolutely, it should not impact the layout of any site. The CSS also has extensive (and arguably necessary) usage of the !important property to greatly reduce any styles undoing the invisibility.

The DIV is also an ARIA live region. Through the combined used of the ARIA attributes aria-live="polite" and aria-atomic="true", the browser will inform screen readers of any non-empty updates to the DIV's text. Note that this live region is polite in that the message will not interrupt any other messages from the screen reader. The live region is also not given an ARIA role as none of the currently available roles are appropriate. This messaging library should NOT be used for critical announcements that would fall under a role="alert" situation.

The ScreenReaderMessenger Object

The ScreenReaderMessenger Object Anchor Link

Just creating a live region is not enough to provide dynamic messaging to screen readers. The ARIA live region we created only announces additions to the text content but NOT any deletions. This works to our advantage. When the say() method is called, the DIV's text content is initially reset to the empty string. This does not get announced because it is not an addition to the text. Then, the message is placed in the DIV. This triggers the live region to inform the screen reader of the new content. This also means that the same text message can be communicated multiple times as the reset then update process always triggers an addition.

However, there is a problem with this approach. Because the DIV's content is not hidden to everyone, that text may be found inconveniently through actions such as selecting all the text or using a browser's find in page features. Thus, it is prudent to always erase the DIV's text content eventually. The timing of this is tricky, though. Some screen readers will cease reading the text if it is deleted while being outputted. Thus, you need to delay the erasing using a call to the setTimeout method in JavaScript.

The SRM handles this delayed erasing as well as making sure no erroneous timeouts accidentally erase the text while it is being read out loud. The internal variable ERASE_DELAY defines the delay, currently set to 5000 milliseconds (5 seconds). This delay mostly suffices assuming that any message is concise enough. However, if the screen reader's speech rate is set too slow, messages may be cut off. If users report this is a problem, increase the erase delay.

Thanks go to Alex Umstead for develop his CodePen for creating a global live region and his conversations about the code itself.