The problem with autocomplete and how to fix it
Tags: a11y, html, javascript, webdev
Published: 2021-01-13 09:33:33

## About

Autocomplete is an amazing tool for your website. It helps your users find what they're looking for, *much* faster than they would if they typed everything and clicked the Search button. 

For example, if I'm using a search engine for capital cities called "Capital Search" to search for "Nicosia", instead of typing the whole name and clicking Search, I can just type the first 2-3 letters ("nic") and the result will show up right under the text box. Now I can just click it and it will take me straight to the website!

![Autocomplete showing the result for Nicosia](https://dev-to-uploads.s3.amazonaws.com/i/ui2rtgousdyrxuruwvo0.png)

[*Interactive page available on CodePen*](https://codepen.io/SavvStudio/full/jOMeVOm)

However this instant interaction with your users comes with a small but important issue.

## Quick overview of our autocomplete code

Before we explore the problem with autocomplete, let's explore how our code currently looks like. The [full code is available here](https://codepen.io/SavvStudio/pen/jOMeVOm). The way it works is quite simple:

1. The user types on the input field
2. Every time they type, a list of capital cities is filtered to get a list of all capital cities starting with the user's input string. For example if I type "n", the cities of "Nassau", "Nicosia", "Nairobi" etc. get returned as search results.
3. The results are shown as a list under the input box.
4. Clicking on an item takes the user to the city's Wikipedia page.

## The problem

The issue with autocomplete has to do with [accessibility](https://dev.to/savvasstephnds/series/10747), specifically with screen reader software. Every time a user types on the input box, the state of the page changes: the results from autocomplete are updated and presented to your user. 

![Progression of autocomplete search results while typing the word "Amsterdam"](https://dev-to-uploads.s3.amazonaws.com/i/f0q80kaq1yabvwjmvkia.png)

However, the screen reader **does not recognise this as an action to tell the user about**. It will announce the header ("Capital Search") and the input box when they gain focus, but not the search results. 

You, as the developer, will need to put something in place in order to tell the screen reader user how many results have been found while typing the search.

## The solution: "Live regions"

The solution for this problem is what we call an ["ARIA live region"](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions). We're basically using the `aria-live` tag to create a `<div>`. Whenever this tag is included, the screen reader will announce any change happening to its contents. It looks like this:

```html
<div role="region" aria-live="polite">0 results found</div>
```

If the content changes to "2 results found", the screen reader will let the user know.

### Updating our code

Now we need to update our code from the CodePen link above to include our live region.

First, let's add the region to our HTML:

```diff
<div id="page">
  <div id="container">
    <h1>Capital Search</h1>
    <div id="search">
      <div id="autocomplete">
        <input type="text" id="query" onkeyup="respondToSearchboxChange()"/>
        <ul id="results">
        </ul>
      </div>
    </div>
  </div>
    
</div>
+ <div id="live-region" role="region" aria-live="polite"></div>
```

Now we need to update our Javascript code to update our live region every time there's a change in search results:

```diff
function respondToSearchboxChange(){
  var input = document.querySelector("#query").value
  
  var searchResults = []
  
  
  if(input.length > 0){
    searchResults = capitals.filter((capital) => capital.toLowerCase().startsWith(input))
  }
+  
+  document.querySelector("#live-region").innerHTML = `${searchResults.length} results found`
      
  document.querySelector("ul#results").innerHTML = searchResults.map((result) =>
    `<li><a href="https://en.wikipedia.org/wiki/${result}" target="_blank" rel="noreferrer">${result}</a></li>`
  ).join("")
}
```

Finally, since we don't want the region to be visible on the page itself, we are going to hide it using CSS:

```css
#live-region{
    position: fixed;
    top: -100px;
}
```

[Full code available on CodePen](https://codepen.io/SavvStudio/pen/YzGJRRE)

That's it! Your autocomplete is now ready and accessible to screen reader users. Every time the result count changes, the screen reader will let the user know. Awesome!

Let me know, either here or [on Twitter](https://twitter.com/SavvasStephnds), how you found this tutorial. Have it helped you make your autocomplete function more accessible?