Dynamic Content: when to use what and why
Today's focus was on dynamic content, AJAX, and single-page applications.
The most relevant topic to my career was how best to notify users of changes when designing interactions related to filling out, validating, and editing forms that post to large data tables to run reports.
Three major methods were mentioned, and I wanted to go through each to better define their real-world relevance, provide a specific example, and an additional short-list of scenarios that would be good and bad in which to be used.
Method 1: Load a New Page or Reload Current Page
Loading a page or reloading the same page to display new content would allow the screen reader user to start reading the entire page again from the top. This is why it's important to keep a status/summary in the title to help assess the page before tabbing through it.
Best scenarios for this use:
- the form I submitted requires the page to refresh in order to display the information I just entered
- the information I just entered was just one step in a process that is carried out over several pages before completion
- if a form being completed returns errors that need to be corrected before resubmitting
- the form submitted is simple so that any errors would be easy to summarize in the page title
When not to use:
- when data could be lost if the page refreshes
- if there is no reason to refresh the page based on the users' actions
Real-world scenario:
I'm on a website to register for an online course, and the first page of the sign-up process requires me to enter my demographic information and a username. I fill out 15-20 fields before hitting the submit button, and the username value isn't able to be validated onblur or in real-time, I need to hit submit in order to check if the username I entered is even available.
When I hit submit, the page refreshes and I hear my screen reader announce in the title of the page "Error: username is already taken." I use a "skip to main content" link, and/or tab to the username field to try again.
What would be even better in this specific scenario, is if above the username field there was a container that produced suggested usernames that were available. Knowing now that I could be stuck in a loop of validation trying to find an available username, making suggestions would significantly improve my experience completing this task.
Method 2: Move the Focus
Sometimes actions for form validation require a submit action and can't happen in real-time. Users need to be brought to the right place with the focus set automatically in order to keep this experience streamlined and address the new content.
Best scenarios for this use:
- when errors or messages can be displayed in a modal/dialog
- with AJAX
- user actions that produce a modal/dialog in which they need to interact to proceed
- inline containers that produce error messages on submit that can't be validated in real-time
When not to use:
- on success notifications that require no action (these can use a role="alert" to announce a successful action)
- when the error notification or content placement makes it harder to address the specific errors on the page (ie: not at all within context to the field in error)
Real-world scenario:
I'm adding a new client record in a drawer from a report page. The drawer contains about 20 fields, and some have relationships to selected values that can only be checked after I hit the submit button. When I select submit, inline error containers are inserted above each field with the error explained in them, and my focus is automatically set to the first error container in the drawer. I'm able to tab through the rest of the drawer to find the other errors as they appear in the DOM before cycling back to the submit button and resubmitting.
These error containers would have to load content with AJAX, have a tab index of -1, and have a 1-2 second delay between when the content was loaded and focus was set to the container.
Additionally, instead of inline error containers, there could be one container at the top of the drawer to provide a summary of the issues as well as links for the user to directly navigate to the field in question. This method may be easier to program because there would be a consistent place for the error information to populate in the drawer, and the user could navigate to it easily with a keyboard shortcut depending on the type of heading/landmark used on the container.
Method 3: Use ARIA Live Announcements
ARIA live announcements are fairly lean compared to the focus method. They do not move focus and do not load/reload the page.
Best scenarios for this use:
- when working with custom widgets/events
- communicating short, temporary statuses for users (ie: success on task completion)
When not to use:
- the message needs to stay on the page and be referenced more than once
- if you need to interact with content inside the message in order to resolve the issue that triggered it
Real-world scenario:
I've just completed a lengthy form after correcting several errors, and it's successfully added to the data table. My screen reader says, "Alert. Successfully added Arthur Dent to the client list," and then begins to read from the top of the page.
This container had a role="alert" and presented as aria-assertive on the page. It also visually disappeared after 5 seconds, and my focus was not moved to it. This success alert region was present on the page but hidden until there was content to place inside it from the form submission.