Enhancing Accessibility in AJAX Dynamic Content

Dynamic content is content that changes based on the behavior, preferences, and interests of the user.  Our websites are full of dynamic content that is powered by JQuery, JavaScript, and Ajax.   All of these can work independently and together to create dynamic content to be generated on the fly based off of user interaction, selections, and preferences.

Notifying Users of Changes

Whenever content changes on a page the user should be notified of the change that has occurred.  This is important so that users who have visual disabilities and those that use assistive technology are aware that the content has in fact changed and that it might be different than what they previously encountered. There are a handful of ways for us to notify a user that content has changed.

In order to notify our users that content has in fact changed we have three ways we can do this to be accessible for our users.  The first way we can notify a user that content has changed is by forcing the user to load a new page or to reload the current page for the new content to be displayed.  We can also notify a user by moving the focus to the updated section and our third and final way to notify our user of a change in content is by having an ARIA live region notify our user of the change that has occurred. 

 

Load or Reload Page

The first way we can notify a user of new content is the easiest way and that is to load or reload the page we are on which will update specific content to reflect the changes.  This is one of the oldest methods and doesn't require JavaScript in order to implement.

Assistive technology users when a page is loaded or reloaded experience a couple things.  The first is that the assistive technology is going to read the page title to them again, next it is going to provide a summary of features on the page such as what headings are there how many regions and links are present, then the assistive technology is going to start reading the page from the top to bottom. 

Because of these actions it is important that when a page is loaded or reloaded due to content changes that the page title is accurate and is a direct result of a user action.  This can be helpful for things like a submission form that has errors, the title of the page when it is reloaded could reflect the number of errors on the page. 

We also want to make sure that we continue to provide the skip to main content so that users can easily navigate and access the new or updated content that is on the page.  We don't want users to have to go through all of the header or sidebar information to get to the changed content. When this is used it is important that the destination of the skip content button has a tabindex of –1 so that it works consistently across all browsers. 

Move the Focus

Moving of the focus is typically applied to things such as dialog boxes that pop up for the user to interact with. The first thing is that our container must have a tabindex of –1.  This is similar to skip navigation when tabindex is not set to –1 the focus will not uniformly be passed to the dialogue box in all browsers equally we want to make sure that wherever the focus is being sent that it is not an empty container.  If the container is empty when the focus gets placed there then the screen reader or assistive technology will not be able to read anything to the user.

We also want to make sure that when we are moving focus that it is not being moved unexpectedly. Focus should always be moved based on a user-initiated action or some kind of critical event that needs immediate attention by our user.  Focus should not be moved for things like announcements, there are better ways such as ARIA live regions to make general announcements to our user without their focus being adjusted.

When we do have to move focus the focus moving should be the last event and it is best practice to delay before sending the focus.  This pause allows AJAX, JavaScript, and other coding languages to finish rendering content on to the page.  If you send the focus immediately content could potentially not be loaded, and the user will only get the blank elements.  The pause is important to ensure that our users do not encounter blank content. 

ARIA Live

One way that we can convey information to our users without reloading our page is with ARIA Live regions, these regions make announcements to our assistive technology users without having to reload the page or moving the users focus elsewhere on the page.    Sometimes this is the only real way to convey information to our users.   These live regions are semantic HTML containers such as <div>’s or spans that have been marked as a region, these elements typically start out empty and then are filled using JavaScript and when this happens, they announce to our users the content that is in the elements.

There are essentially two types of ARIA Live announcements, and they are assertive and polite.  Assertive announcements will interrupt the user immediately to make the user aware of the information where polite will wait until the assistive technology has completed its task to announce the information to the user. There is a third type of ARIA announcements that can impact a user’s and that is with the role attribute.  When we apply role="alert" the assertive type of ARIA live will also automatically be attached to the region but prior to the announcement the user will hear the assistive technology say "Alert".

If should be mentioned that regardless of the ARIA live region the message should be short due to if the message is interrupted by anything the user will not be able to get back to it and it is best practice after the user has moved on that the region is then deleted out so that the user does not encounter old information that is no longer relevant for their interaction with the system. These regions can be made visible to all users or made specifically for assistive technology users.  It is important to determine the purpose and if it is needed for all users or not prior to building out the announcement regions. 

Time Limits and Session Timeouts

When we talk about time limits we primarily talk about 3 items.  We are talking about session timeouts, timers that may have fixed deadlines, those that auto refresh or reload.  Let’s take a look at each of them in depth. 

Users regardless of what the session is should be warned before their session ends.  The most common way we do this is with a dialog box that provides the user with the option to extend the session or to continue to let the session expire.  This is frequently seen on sites that have sensitive data such as banking sites.  The warning should be shown to the user with enough time left for the user to respond, best practice is to notify the user about the session expiration and extension at roughly 2 minutes left, this allows most users the ability to make a selection to continue their session or to allow it to expire. 

If a session needs to expire for a user, then we must make sure that any data that they are entering is being saved so that when they come back their information will be available to them to continue the process.  This is important, there are certain times when this isn't possible but every attempt to make this default functionality is important. 

Browser History Code with Ajax and JavaScript

We also want to make sure that our users are able to use the back button after a new page seems to be loaded, this means that we need to use JavaScript code to cause the browser to log a history change. If we do not use JavaScript to cause this then we will not be able to use the back button to reverse our path.  This is something that needs to be implemented and thought about to be done properly. The easiest way to do this is with JavaScript code.

Set History Function
var newUrl = 'URL THAT YOU WANT';
var newTitle= 'TITLE THAT YOU WANT';
history.pushState({ url: newUrl, title: newTitle },
newTitle, newURL);
Browser Back and Forward Button Code
$(window).on('popstate', function(e) {
var state = e.originalEvent.state;
if (state !== null){[CODE] } 

else{ [CODE] }
});