This content originally appeared on Scott O’Hara - Accessibility engineer, UX developer and designer and was authored by Scott O'Hara
Before we even begin, here are some key things I want you to take from this post that I had intended to write as a quick note… but I clearly don’t know how to not just explode words everywhere.
Some quick takeaways
Concerning UI where content is dynamically displayed or filtered based on user input from a text field:
- Provide people an instructional cue (accessible description) that "results will [adjective] as you type" for search components that dynamically render results. Use the words like "filter", "display", both or similar depending on the functionality of your component.
- Live regions only communicate strings of text. If you need to convey information that has important semantics or other accessibility information, a live region is likely the wrong way to do it.
- Constantly interrupting a user as they type with a live region should be avoided. Thus constantly announcing how many results are shown is not the best UX.
- Some people might need more time to enter a search query due cognitive or motor disabilities. Some people might quickly type what they want and then navigate away from the text field before any dynamic announcement is made. Again, another reason to not rely heavily on live regions.
- Do ensure that an assertive live region is used to immediately inform a user that no results were found. This is the one time we DO want to interrupt people, so they don't waste time typing when their query has already failed.
- A live region will have the most robust support if it is an empty live region that is populated with content, rather than the live region itself being injected when rendering a message.
- Consider other UX improvements that will help people quickly navigate your UI, which feel natural but also won't disrupt expected functionality for other controls.
It has become common place for people to be presented with web interfaces where one can type into a search or filter text field, and a script can runt to (almost) immediately return relevant results on the same page.
Such an interface is useful and provides an immediacy to slower experiences of days past. Rather than require people input their query, hit submit, wait for the new page or screen of results to return and then they can determine if the results contain what they want or not… dynamically display the results, or filtering down already displayed content cuts out all the waiting.
Please note, the described UI is not referring to autocomplete text fields / comboboxes.
more info and spoilers
This post is specifically going over a search or filtering UI where people can type into a text field and immediately see results display, filter, or both on the current web page. You can see an example of this at a11ysupport.io.
Spoilers: a11ysupport.io employs a lot of the accessibility considerations this post outlines. Thanks @mfairchild365.
Of course, this then begs the question of how do you convey such information to people who use assistive technologies, such a screen readers. If someone cannot see the page, how will they know when results are dynamically returned, let alone that results are going to be rendered at all?
If you are familiar with web accessibility, and in particular ARIA, you might be thinking “use a live region!”
If you are familiar with live regions, such a blanket recommendation might make you think “for the love of everything you hold dear, please do not use a live region!”
One thing at a time
Let’s back up a second and level set on the situation and come to a few base understandings.
First, live regions
Live regions are used when you need to communicate information that is being presented visually, but someone using assistive technologies (AT) might not be aware of. The situations where this would occur are for people with low or no vision, where they are specifically focused or scanning or interacting with one part of a web page, but the dynamic update is occurring somewhere else. Similarly, people with low vision who might be looking at a zoomed in, or magnified portion of their screen, but the updated visual occurs outside of their current area of visibility.
A live region can be used to communicate this information to these people if they are using AT, such as screen readers, which can ‘listen’ for dynamic changes that are exposed via live regions. However, even with live regions there are limitations to what will be communicated.
For instance, live regions are a good tool for communicating a simple string of content. E.g., “your information has been saved!” or “there was a problem with X. Please try again.”
Live regions are rubbish if you need to communicate large swaths of information, or information that would best be communicated by other semantics and accessibility properties. This is because live regions only communicate strings of text.
For example:
<div aria-live="polite">
<button>You'll have to guess what I represent!</button>
</div>
The text of the <button>
would be announced when it was injected into the live region. The fact that the text represents the label of a button would not be communicated… as there would be no mention of the button’s role in the live region announcement.
Now, the reason I mention all of that is because a common misunderstanding about how to communicate the returned results for dynamic filtering of content or search results is to wrap all of said content in a live region.
No. Gross. Never.
Consider the following:
<label>
Search help articles
<input type=text>
</label>
<h2>Results:</h2>
<div aria-live="polite">
<ul>
<li>
<a href="...">Title of article</a>
<p>maybe some description goes here</p>
</li>
<li>
<a href="...">Title of article</a>
<p>maybe some description goes here</p>
</li>
...
</ul>
</div>
If the above results were injected into a live region, someone using a screen reader would hear a flattened text string of the content as a single uninterrupted announcement. Assuming the native bullet list markers have not been removed from the results list, the announcement could resemble the following:
“bullet, Title of article maybe some description goes here. bullet, Title of article maybe some description goes here …”
So that’s awful.
And because I like making silly comparisons to explain information, it’s awful because it would be like someone asking you how many pages are in a book. Then, rather than give a concise answer, you instead shout at them the entirety of the written contents of the book. You do this until they literally tell you to shut up (Ctrl key), or until you run out of air and collapse.
OK, point taken. So instead we should let people know just that content has been updated, or let them know the specific number of results that are being dynamically displayed. Right?
Not quite. Not yet…
Second, I’m typing. Don’t interrupt me… well, unless…
Another thing to keep in mind about this particular use case, is that someone is actively trying to input their query into a text field. Imagine trying to write out a word. After every character you type, the UI keeps interrupting you to say that results are shown.
That might be helpful. Once. And if you weren’t already aware that this is how the component behaves. But, doing that after every single character entry? That gets annoying fast.
We don’t want to constantly interrupt and distract people as they type. Additionally, unless there is a number of returned results displayed in text – it’s rather pointless to convey how many results are being rendered. This is particularly true when the results may be so great that the total number would be unknown, even if one could see the whole screen at once.
Now, arguably there is value in letting people know when they have filtered results down to just a few instances. But even if waiting until only a few results are shown, interrupting announcements are still interrupting announcements.
Who’s to say what number is the number where it becomes OK to start such behavior? Some people might want 10? Maybe five? What if all the results are very similar even at five, and the best way to make sure the right result is returned is to just finish the phrase?
A solution to frequent interrupting announcements could be to only announce after a delay of inactivity. For instance, a live region could remain empty until a long enough delay has been detected since the last key press. But what is “long enough” will depend on the person. Some people might need more time to type due to cognitive or motor disabilities. Some people might quickly type what they want and then navigate away from the text field before an announcement can even be made.
Another thing to consider: we don’t want to be disruptive with conveying general content updates as people are typing. But, do want to immediately let someone know when they have entered a query that returns no results.
Delaying this an announcement of this information would result in wasted time, and potential uncertainty about ‘when’ someone’s query stopped working. Was it because of a typo? Was it because of an added word that made their query too specific? People without vision disabilities are likely to notice right away when the dynamic content dries up, and they can immediately correct for this by adjusting their query. This same affordance must be provided to people with disabilities.
A proposal
People want and need different things. So, rather than try to come up with the perfect live region solution and determine the amount of time necessary to delay such dynamic announcements, which will never please everyone, I instead propose the following:
<label>
[ accessible name/label for field ]
<input id=field aria-describedby=info>
</label>
<!-- ... -->
<h2 tabindex=-1>
Results for [query]
<span hidden># available</span>
</h2>
<div id=info>
<!-- may be visual or hidden depending on persnickety individuals -->
Results will update as you type.
</div>
<div aria-live=assertive aria-atomic=true>
<!-- if no result found, inject that message here -->
</div>
<!-- markup for rendering search results goes here -->
The text field
Use a text field or search field with a proper visible label as appropriate for your UI.
Provide that field with a description to indicate that “results will update as you type” (or some similar verbage that your content team can decide upon. People are so picky with their words…).
In the markup snippet above, aria-describedby
is used to associate the description of behavior with the text field. Ideally this description is visible to everyone, as it informs everyone of what to expect. However, pick your battles if need be, and if this cannot be visible because people value their opinions over usability, then just make sure the description is programmatically associated with the form field.
When someone navigates to the text field, the description can be conveyed to their assistive technology. This will inform this person of the behavior they can expect. Telling someone this up front sets expectations, allowing content to update without needing to constantly inform them that such content will update.
Arguably, one could make a case for appending this behavior to the end of the field’s accessible name. A valid reason being some people turn off the automatic announcement of element descriptions. I’m personally of two minds on this, as I do think it’s important to inform people of the behavior… but such information can become unnecessarily redundant the more someone is used to interacting with a particular UI.
For instance, how many of us really benefit from being informed what seat belts are, and how they work every time we travel by airplane? Adding instructions to the accessible names of controls is like that. I prefer the route of providing the necessary information, and allowing the individual to easily ignore, or not.
The results / dynamic content section
Moving on… introducing the search results with a heading will allow people a consistent location they can expect results to populate in. This benefits everyone in the end. But people who use screen readers generally get a lay of the land (or the DOM… whatever) when they come to new web pages. Much like someone with full vision will quickly glance around a web page to get at least a basic understanding of the information presented.
I don’t care to be prescriptive in the manner in which you markup your search results. Whether they be a list, or a series of headings containing links with a descriptive sentence for more context… both can be valid, so have at it.
Communicating no results
While I’ve been clearly against using live regions to constantly interrupt people as they type, there is benefit to interrupting someone when no results are found. In such a case where no results are found, a status message is typically displayed which indicates this state. WCAG 2.1 requires we announce status messages.
The live region is an empty <div aria-live=assertive>
. I suggest having a generic live region rather than using a specific live region role
.
Context for suggesting a generic live region
I personally don't see much of a reason to use a role for such a message, but I specifically don't want to use a role=alert
.
While an alert
would create an assertive live region, some screen readers and browsers will immediately announce the existence of an "alert" on page render (I'm specifically looking at you, TalkBack).
Essentially, an "alert" announcement will be made immediately (the element's role). But as it has no content yet... because nothing's gone wrong at this point, there's no indication as to why this "alert" was announced.
Granted, such behavior should be considered a bug... but I don't want to deal with that nonsense. There's too many other things to worry about, so I suggest we just avoid in this instance. Do file a bug if you like, though :)
Due to live regions being notoriously awful at being announced when injected into a web page, ensure an empty live region that content can be injected into exists in the DOM. Using live regions in this manner offers the most robust support to ensure their announcement will be made by as many screen reader and browser combinations as possible. (someday I’ll get around to finishing the post where I outline some data on this)
Wait. What happens if I press Enter?
Ah, good question. That’ll depend on the type of search component you are creating. Essentially, there are two types of dynamic search or filtering components.
First, there may be instances of components like these that return “quick results”. Someone entering their query might get common suggested results, but if they hit enter, or activate a “submit button”, the query will be sent and a full results page will be rendered. So in that case, Enter essentially works as generally expected. It submits the search query.
For the second type, there is no actual submission. Results are only shown and filtered on the current page. There is no formal submission of a query. But muscle memory is weird… and unless you explicitly mention that there is no form submission, people might try it out anyway.
Most will then realize, when a whole bunch of nothing happens, that what they get is what they get. They’ll then move on and start interacting with the content of the page.
But, we could go beyond the bare minimum of making a WCAG-conforming user experience and provide some extra functionality for people who might want or expect Enter to do something?
Just because WCAG says you only have to give someone a turkey sandwich, that doesn’t mean you can’t give them condiments to go with it.
By listening for an Enter key press, JavaScript can programmatically move focus to the heading that introduces the result listing. If placing the number of found results within the heading, then that information will be announced along with the static heading text.
const field = document.getElementById('field');
field.addEventListener('keyup', function ( e ) {
if ( e.key == 'Enter' ) {
heading.focus();
}
});
While we’re at it, why not provide a quick mechanism to return to the search field as well? In discussing this pattern with my coworker, he found himself wanting to press the Esc key to return to the search field. Even though he was aware that was unexpected functionality for such a UI, it just seemed to fit how he’d expect this to work.
Now, one person’s expectation doesn’t make for a standard, but it was a good idea. More importantly, implementing this functionality generally won’t disrupt anyone’s experience, and it’ll be useful for those who had similar expectations.
heading.addEventListener('keyup', function ( e ) {
if ( e.key == "Escape" ) {
field.focus();
}
});
The one caveat to this is to make sure that if you have this UI within a dialog, or some other form of “popup” that will close if pressing the Esc key, that you make sure to suppress this functionality when the heading is focused.
The outcome
And with that, the following represents a quick demo of expected behavior. The same results will return no matter what you enter into the text field, and a no results found message will appear as soon as more than 5 characters are detected in the text field.
See the Pen quick demo of showing / informing about dynamic results by Scott (@scottohara) on CodePen.
You can also check out a11ysupport.io which has implemented ideas from this post into the search/filter field there. You know, if you want to check out a real example, rather than my sloppy demo trash :)
This content originally appeared on Scott O’Hara - Accessibility engineer, UX developer and designer and was authored by Scott O'Hara
Scott O'Hara | Sciencx (2022-02-05T00:00:00+00:00) Considering dynamic search results and content. Retrieved from https://www.scien.cx/2022/02/05/considering-dynamic-search-results-and-content/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.