Day 24: Making autocomplete search accessible for React apps with Downshift
Tags: webdev, a11y, react, autocomplete
Published: 2023-02-07 01:08:59

## TL;DR

To equip your React app with _accessible_ autocomplete search, use the `useCombobox` hook from the [Downshift](https://www.downshift-js.com) library. It makes web developers’ life a lot easier than coding from scratch. This article reviews the HTML code for accessible autocomplete search (Section 2) and then describes how we can use Downshift to generate it (Section 3).

![Initially, only a search box is shown with the text cursor flashing in it. Then the letter "s" appears in the search box, and five autocomplete suggestions are revealed below the search box: San Francisco, Sapporo, Seoul, Singapore, and Stockholm. Each is alternately highlighted in sequence. Finally, the word "Stockholm" appears in the search box while the five suggestions disappear.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j0ilzonykdx7wsqi8aw9.gif)
**The user experience this article aims to implement when the user (1) types "s", (2) presses the Down Arrow key five times, and (3) hits the Return key.**

## 1. Introduction

_My Ideal Map_, a web app I’m building, relies on Google Maps’s autocomplete search: whenever the user types a character in the search box, the app suggests the list of place names that the user may be looking for.

And I want to implement the autocomplete search feature with accessibility in mind and by using React. Learning about how to make autocomplete search accessible, however, I find it daunting to code from scratch. So it is worth exploring the possibility of using an external library that is battle-tested enough to minimize the number of bugs.

[Downshift](https://www.downshift-js.com), a library that I learned about while I was watching video tutorials from [Epic React](https://epicreact.dev), fits the perfect bill. It does all the tedious jobs for accessibility behind the scene. Plus, it is easy to customize for my specific needs, with the customized code easy to maintain.

In this article, I explain how I use Downshift to equip my React app with accessible autocomplete search.

## 2. HTML for accessibility

Before getting into the detail of Downshift, let’s review what the HTML code should look like for accessible autocomplete search.

Browsing [_ARIA Authoring Practices Guide_](https://www.w3.org/WAI/ARIA/apg/), I’ve figured out that the example entitled "[Editable Combobox With List Autocomplete](https://www.w3.org/WAI/ARIA/apg/example-index/combobox/combobox-autocomplete-list.html)" is the closest to what we know as autocomplete search.

Here is what I have learned:

### 2.1 Default
Before the user enters text in a search box, the HTML code should be something like this:
```html
<label for="cb1-input">
  Search a place on the map
</label>
<input
  aria-autocomplete="list"
  aria-controls="cb1-listbox"
  aria-expanded="false"
  id="cb1-input"
  role="combobox"
  type="search"
/>
<ul
  id="cb1-listbox"
  role="listbox"
  aria-label="Autocomplete suggestions"
>
</ul>
```
It is the standard practice to link up the `<label>` element’s `for` attribute with the `<input>` element’s `id` attribute (so the screen reader user can tell what the `<input>` element is for). And with the `type="search"` attribute, iOS and Android change the mobile keyboard’s Return key label into “go” and the magnifying glass icon, respectively (see [Alex Holacheck’s little demo](https://better-mobile-inputs.netlify.app/?android=true&autocomplete&inputmode&type=search)).

Specific to autocomplete search is the combination of `role="combobox"` and `aria-autocomplete="list"`. These two attributes together tell the screen reader user that this search box (i.e., `<input type="search"/>`) will pop up the list of autocomplete suggestions once the user enters text in it.

But the screen reader user needs to know where the popup list is. The `aria-controls` attribute does this job, by referring to the `id` attribute of the popup list, typically the `<ul>` element as shown in this example.

The `aria-expanded="false"` tells the screen reader user that the popup list is currently hidden.

The `<ul>` element has the `role="listbox"` attribute, which tells the screen reader user that it serves as the popup list of autocomplete suggestions.

The [_ARIA Authoring Practices Guide_](https://www.w3.org/WAI/ARIA/apg/example-index/combobox/combobox-autocomplete-list.html) isn’t explicit about whether the listbox element should be in the DOM by default or not. However, the [Downshift’s documentation](https://github.com/downshift-js/downshift/tree/master/src/hooks/useCombobox#getmenuprops) briefly mentions that it should for accessibility reasons. So I follow this advice.

### 2.2 Once search text is entered
Once the user enters text in the search box, the HTML code should change into somethinig like this:
```html
<label for="cb1-input">
  Search a place on the map
</label>
<input 
  id="cb1-input"
  type="search"
  role="combobox"
  aria-autocomplete="list"
  aria-controls="cb1-listbox"
  aria-expanded="true"        // CHANGED! 
/> 
<ul
  id="cb1-listbox"
  role="listbox"
  aria-label="Autocomplete suggestions"
>
  { /* ADDED FROM HERE */}
  <li id="lb1" role="option">Suggestion 1</li>
  <li id="lb2" role="option">Suggestion 2</li>
  <li id="lb3" role="option">Suggestion 3</li>
  <li id="lb4" role="option">Suggestion 4</li>
  <li id="lb5" role="option">Suggestion 5</li>
  { /* ADDED UNTIL HERE */}
</ul>
```

The `<input>` element’s `aria-expanded` attribute turns into `true`, as the popup list of autocomplete suggestions is now shown.

The `role="option"` in each `<li>` element tells the screen reader user that it represents one of the autocomplete suggestions.

### 2.3 When the keyboard user selects an autocomplete suggestion
Now, suppose the keyboard user (which of course includes the screen reader user) selects “Suggestion 1” with the Down Arrow key. This should transform the HTML code into something like this:
```html
<label for="cb1-input">
  Search a place on the map
</label>
<input
  id="cb1-input"
  type="search"
  role="combobox"
  aria-autocomplete="list"
  aria-controls="cb1-listbox"
  aria-expanded="true"
  aria-activedescendant="lb1"      // CHANGED!
/>
  <ul
    id="cb1-listbox"
    role="listbox"
    aria-label="Autocomplete suggestions"
  >
    <li id="lb1" role="option"
      aria-selected="true"         // CHANGED!
    >
      Suggestion 1
    </li>
    <li id="lb2" role="option">
      Suggestion 2
    </li>
    <li id="lb3" role="option">
      Suggestion 3
    </li>
    <li id="lb4" role="option">
      Suggestion 4
    </li>
    <li id="lb5" role="option">
      Suggestion 5
    </li>
  </ul>
</div>
```

The `<input type="search">` now has an additional attribute `aria-activedescendant`, which refers to the `id` attribute of the selected `<li>` element.

The selected `<li>` element has an additional attribute `aria-selected="true"`, to indicate that it is selected by the user.

By hitting the Return key, then, the selected item is chosen by the user. 

### 2.4 Implementing with React
How can we implement with React the above-described changes of HTML code for autocomplete search? Doing it from scratch appears to be a daunting task. 

Luckily, I’ve found a rescue: [Downshift](https://www.downshift-js.com), a library written by Kent C Dodds and others for React apps.

## 3. Downshift

Downshift, by default, is designed to create the user experience where _clicking the text field_ will reveal autocomplete suggestions. This behavior is ideal for the user to choose a country of residence from the predefined list, for example. 

But it is slightly different from what I want to implement with the place search of Google Maps API. I want _typing the first character of search text_ to reveal autocomplete suggestions. 

So I need to tweak a bit the [code snippet provided in Downshift’s documentation](https://www.downshift-js.com/use-combobox#basic-usage). Here’s how.

### 3.1 Setting up
Let’s first install the library with NPM: type the following in Terminal:
```bash
npm install downshift
```

For this article, I have installed Downshift v7.2.0. Its future versions may change what follows below.

Then, at the beginning of a React component file for the search box (let’s call it `SearchBox`), import the `useCombobox` hook:
```js
import {useCombobox} from 'downshift';

export const SearchBox = () => {
};
```
### 3.2 Managing autocomplete suggestions as React state
Whenever the list of autocomplete suggestions changes, the UI also needs to change. This means that the array of autocomplete suggestions is best to be managed as a React state the change of which triggers the rerendering of a component and thus the updating of user interface:

```js
import {useState} from 'react'; // ADDED
import {useCombobox} from 'downshift';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); // ADDED
}
```

### 3.3 `<input>` element markup
To implement the default HTML code for the `<input>` element as described in Section 2.1 above, we use the `getInputProps` method from the `useCombobox` hook:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  // ADDED FROM HERE
  const {getInputProps} = useCombobox({
    items: autocompleteSuggestions
  });
  return (
    <input {
      ...getInputProps()
    }>  
  );
  // ADDED UNTIL HERE
};
```
where the `items` option, required for the `useCombobox` hook to work, refers to the array of autocomplete suggestions. The `getInputProps` returns an object whose properties are the HTML attributes for the `<input>` element. Consequently, the above code renders the `input` element as follows:
```html
<input
  aria-activedescendant=""
  aria-autocomplete="list"
  aria-controls="downshift-1-menu"
  aria-expanded="false"
  aria-labelledby="downshift-1-label"
  autocomplete="off"
  id="downshift-1-input"
  role="combobox"
  value=""
>
```
My React app requires a few more attributes to the search box. I can specify them as the options for `getInputProps()` as follows:
```js
getInputProps({
  inputMode: "search",
  placeholder: "Enter place name or address",
  type: "search"
})
```
As described in Section 2.1 above, the type="search" attribute makes the iOS/Android mobile keyboard appropriate for a search box. The inputMode prop (see [Oliff 2019](https://css-tricks.com/everything-you-ever-wanted-to-know-about-inputmode/#aa-search) for detail) is a fallback when the mobile keyboard does not change as expected (which happened to me with [Styled Components](https://styled-components.com) for some reason). And the `placeholder` attribute is handy to suggest what to enter.

Also, I want to add two more attributes to the `<input>` element. First, I want the search box to be auto-focused when it is opened. With React, the `autoFocus` prop does the job (see [Johnson 2019](https://blog.maisie.ink/react-ref-autofocus/#time-for-react); see also [**Day 20 of this blog series**](https://dev.to/masakudamatsu/day-20-toggling-a-search-box-for-keyboard-users-with-react-1d0c)):
```js
getInputProps({
  autoFocus: "true", // ADDED
  inputMode: "search",
  placeholder: "Enter place name or address",
  type: "search"
})
```
However, this will turn the `aria-expanded` attribute into `true`, because Downshift, by default, makes it change depending on whether the `<input>` element is focused or not.

Instead I want the `aria-expanded` to be `true` when the user enters any character into the search box, which in turn fills the array of `autocompleteSuggestions` from Google Maps API calls. So I want to check whether `autocompleteSuggestions` has any item in its array:
```js
getInputProps({
  "aria-expanded": autocompleteSuggestions.length > 0, // ADDED
  autoFocus: "true", 
  inputMode: "search",
  placeholder: "Enter place name or address",
  type: "search"
})
```
This way, Downshift allows us to override the default attribute values that it adds.

The other attribute I want to add is `aria-label`. I have designed the search box with the magnifying glass icon in it, which plays a role of the label to sighted users (see [**Day 17 of this blog series**](https://dev.to/masakudamatsu/day-17-styling-a-search-box-like-googles-51d2)). For the screen reader user, then, it is enough to label the search box with the `aria-label` attribute:
```js
getInputProps({
  "aria-expanded": autocompleteSuggestions.length > 0,
  "aria-label": "Search for a place on the map", // ADDED
  autoFocus: "true", 
  inputMode: "search",
  placeholder: "Enter place name or address",
  type: "search"
})
```
However, Downshift, by default, assumes that there is a `<label>` element and uses `aria-labelledby` to refer to the `id` attribute of the `<label>` element. I don’t need it. So I override it with `null`:
```js
getInputProps({
  "aria-expanded": autocompleteSuggestions.length > 0,
  "aria-label": "Search for a place on the map",
  "aria-labelledby": null, // ADDED
  autoFocus: "true", 
  inputMode: "search",
  placeholder: "Enter place name or address",
  type: "search"
})
```

What is great about Downshift is the ease with which we can customize its implementation. Plus, looking at the code clearly tells us what is customized.

Let’s move on to the `<ul>` element.

### 3.4 `<ul>` element markup

To make the `<ul>` element accessible as the list of autocomplete suggestions, we use `getMenuProps()` out of the `useCombobox` hook:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  const {
    getInputProps, 
    getMenuProps   // ADDED
  } = useCombobox({
    items: autocompleteSuggestions
  });
  return (
    <>
      <input {
        ...getInputProps({
          "aria-expanded": autocompleteSuggestions.length > 0,
          "aria-label": "Search for a place on the map",
          "aria-labelledby": null,
          autoFocus: "true", 
          inputMode: "search",
          placeholder: "Enter place name or address",
          type: "search"
        })
      }>
      {/* ADDED FROM HERE */}
      <ul
        {...getMenuProps()}
      >
      </ul>
      {/* ADDED UNTIL HERE */}
    </>
  )
};
```
which renders the `<ul>` element as follows:
```html
<ul 
  id="downshift-1-menu"
  role="listbox"
  aria-labelledby="downshift-1-label"
></ul>
```
Remember that the `id` attribute value, `"downshift-1-menu"`, is used for the `aria-controls` attribute of the `<input>` element (see Section 3.3. above).

The `aria-labelledby` attribute is redundant for my purpose, as there is no `<label>` element. So I make it `null` and add `aria-label` instead:
```js
getMenuProps({
  'aria-label': "Autocomplete suggestions",
  'aria-labelledby': null,
})
```
That’s all for the default HTML code.

### 3.5 Showing autocomplete suggestions

For the ease of exposition, let me first mock autocomplete search with a function called `mockAutocompleteSearch`:
```js
// utils/mockAutocompleteSearch.js
export function mockAutocompleteSearch(searchText) {
  if (searchText === 's') {
    return ["San Francisco", "Sapporo", "Seoul", "Singapore", "Stockholm"];
  } else {
    return [];
  }
}
``` 
If the argument is the string of "s", it returns the list of fives cities whose name begins with "s" that I have been to in the past. It is a stupid function, but it is sufficient to explain how Downshift works with any autocomplete search function that maps from the user’s input to the array of suggestions.

To run this function whenever the user enters text into the search box, we use the `onInputValueChange` option for the `useCombobox` hook:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';
import {mockAutocompleteSearch} from '../utils/mockAutocompleteSearch.js'; // ADDED

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]);
  const {    
    getInputProps, 
    getMenuProps
  } = useCombobox({
    items: autocompleteSuggestions,
    // ADDED FROM HERE
    onInputValueChange: ({inputValue}) => {
      if (inputValue === '') {
        setAutocompleteSuggestions([]);
        return;
      }
      setAutocompleteSuggestions(mockAutocompleteSearch(inputValue));
    }
    // ADDED UNTIL HERE
  });
  return (
    // Omitted for brevity
  )
};
```
The `inputValue` refers to the text the user enters into the search box. If it’s empty, we set the `autocompleteSuggestions` array to be empty. Otherwise, we set the array to contain autocomplete suggestions returned by `mockAutocompleteSearch()`.

We can then use the condition
```js
autocompleteSuggestions.length > 0
```
to decide whether to show the list of autocomplete suggestions:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';
import {mockAutocompleteSearch} from '../utils/mockAutocompleteSearch.js';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  const {    
    getInputProps, 
    getMenuProps
  } = useCombobox({
    items: autocompleteSuggestions,
    onInputValueChange: ({inputValue}) => {
      if (inputValue === '') {
        setAutocompleteSuggestions([]);
        return;
      }
      setAutocompleteSuggestions(mockAutocompleteSearch(inputValue));
    }
  });
  return (
    <>
      {/* The search box is omitted for brevity */}
      <ul
        {...getMenuProps({
          'aria-label': "Autocomplete suggestions",
          'aria-labelledby': null,
        })}
      >
        {/* ADDED FROM HERE */}
        {autocompleteSuggestions.length > 0
          ? autocompleteSuggestions.map((suggestion, index) => {
              return (
                <li
                  key={`suggestion-${index}`}
                >
                  {suggestion}
                </li>
              );
            }) 
          : null}
        {/* ADDED UNTIL HERE */}
      </ul>
    </>
  )
};
```
The use of the `map()` array method is the standard practice for using React to render the list out of an array (see [React Docs on Lists and Keys](https://reactjs.org/docs/lists-and-keys.html)).

### 3.6 `<li>` element markup

Now, to add the relevant ARIA attributes to the `<li>` elements, we use `getItemProps()` out of the `useCombobox` hook:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';
import {mockAutocompleteSearch} from '../utils/mockAutocompleteSearch.js';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  const {    
    getInputProps,
    getItemProps,  // ADDED 
    getMenuProps
  } = useCombobox({
    items: autocompleteSuggestions,
    onInputValueChange: ({inputValue}) => {
      if (inputValue === '') {
        setAutocompleteSuggestions([]);
        return;
      }
      setAutocompleteSuggestions(mockAutocompleteSearch(inputValue));
    }
  });
  return (
    <>
      {/* The search box is omitted for brevity */}
      <ul
        {...getMenuProps({
          'aria-label': "Autocomplete suggestions",
          'aria-labelledby': null,
        })}
      >
        {autocompleteSuggestions.length > 0
          ? autocompleteSuggestions.map((suggestion, index) => {
              return (
                <li
                  key={`suggestion-${index}`}
                  // ADDED FROM HERE
                  {...getItemProps({
                    suggestion,
                    index
                  })}
                  // ADDED UNTIL HERE
                >
                  {suggestion}
                </li>
              );
            }) 
          : null}
      </ul>
    </>
  )
};
```
which will render `<li>` elements as follows:
```html
<li 
  role="option"
  aria-selected="false"
  id="downshift-1-item-0"
  suggestion="San Francisco"
>
  San Francisco
</li>
<li 
  role="option"
  aria-selected="false"
  id="downshift-1-item-1"
  suggestion="Sapporo"
>
  Sapporo
</li>
<li 
  role="option"
  aria-selected="false"
  id="downshift-1-item-2"
  suggestion="Seoul"
>
  Seoul
</li>
<li
  role="option" 
  aria-selected="false"
  id="downshift-1-item-3"
  suggestion="Singapore"
>
  Singapore
</li>
<li
  role="option" 
  aria-selected="false"
  id="downshift-1-item-3"
  suggestion="Stockholm"
>
  Stockholm
</li>
```
I don’t know why Downshift adds the `suggestion` attribute...

### 3.7 When the user chooses one of the suggestions

The final step to comply with the [ARIA Authorizing Practices Guide](https://www.w3.org/WAI/ARIA/apg/example-index/combobox/combobox-autocomplete-list.html) is to deal with the selection of an autocomplete suggestion.

Actually, with the code written so far, Downshift implements the changes of ARIA attributes in response to the keyboard user’s choice of an autocomplete suggestion. Pressing the Down Arrow key to select the first suggestion converts the HTML code into the following:
```html
<input 
  aria-activedescendant="downshift-1-item-0" // CHANGED!
  aria-autocomplete="list"
  aria-controls="downshift-1-menu" 
  aria-expanded="true" 
  autocomplete="off" 
  id="downshift-1-input" 
  role="combobox" 
  aria-label="Search for a place on the map" 
  inputmode="search" 
  placeholder="Enter place name or address" 
  type="search" 
  value="s">
<ul 
  id="downshift-1-menu"
  role="listbox"
  aria-label="Autocomplete suggestions"
>
  <li 
    role="option" 
    aria-selected="true"    // CHANGED!
    id="downshift-1-item-0" 
    suggestion="San Francisco">
    San Francisco
  </li>
  <li 
    role="option"
    aria-selected="false"
    id="downshift-1-item-1"
    suggestion="Sapporo"
  >
    Sapporo
  </li>
  <li 
    role="option"
    aria-selected="false"
    id="downshift-1-item-2"
    suggestion="Seoul"
  >
    Seoul
  </li>
  <li
    role="option" 
    aria-selected="false"
    id="downshift-1-item-3"
    suggestion="Singapore"
  >
    Singapore
  </li>
  <li
    role="option" 
    aria-selected="false"
    id="downshift-1-item-3"
    suggestion="Stockholm"
  >
    Stockholm
  </li>
</ul>
```
Notice the `aria-activedescendant` attribute of the `<input>` element now points to the `id` attribute of the first `<li>` element, which in turn toggles its `aria-selected` attribute into `"true"`.

However, sighted users won’t see anything as I haven’t styled any of the `<li>` elements in response to the keyboard user’s selection.

To do so, we use `highlightedIndex` out of the `useCombobox` hook:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';
import {mockAutocompleteSearch} from '../utils/mockAutocompleteSearch.js';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  const {    
    getInputProps,
    getItemProps,
    getMenuProps,
    highlightedIndex, // ADDED
  } = useCombobox({
    items: autocompleteSuggestions,
    onInputValueChange: ({inputValue}) => {
      // omitted for brevity
    },
  });
  return (
    <>
      {/* The search box is omitted for brevity */}
      <ul
        {...getMenuProps({
          'aria-label': "Autocomplete suggestions",
          'aria-labelledby': null,
        })}
      >
        {autocompleteSuggestions.length > 0
          ? autocompleteSuggestions.map((suggestion, index) => {
              return (
                <li
                  data-highlighted={index === highlightedIndex} // ADDED
                  key={`suggestion-${index}`}
                  {...getItemProps({
                    suggestion,
                    index
                  })}
                >
                  {suggestion}
                </li>
              );
            }) 
          : null}
      </ul>
    </>
  )
};
```
To check whether or not the keyboard user selects a particular `<li>` element with its position given by `index`, we can use the statement `index === highlightedIndex`, which is `true` when selected.

To style the selected `<li>` element, I use the `data-highlighted` attribute whose value corresponds to the evaluation of `index === highlightedIndex`. Then, in a CSS stylesheet, style it something like this:
```css
li[data-highlighted="true"] {
  background-color: var(--highlighted);
}
```
where the color is defined somewhere else as a CSS variable called `--highlighted`.

This way, we can indicate which autocomplete suggestion is currently selected, like this:
![Letter "s" is shown in the search box below which the first suggestion "San Francisco" is highlighted while other four suggestions below, "Sapporo", "Seoul", "Singapore", and "Stockholm" are not.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npk4hk90hrctq718dyrb.png)

### 3.8 When the user selects a suggestion by click
Finally, when the user selects one of the autocomplete suggestions by clicking it, we need to run a script to show the location of it on the map. This is simple: we can just add an `onClick` prop as an additional argument for `getItemProps()`:
```js
import {useState} from 'react';
import {useCombobox} from 'downshift';
import {mockAutocompleteSearch} from '../utils/mockAutocompleteSearch.js';

export const SearchBox = () => {
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState([]); 
  const {    
    getInputProps,
    getItemProps,
    getMenuProps,
    highlightedIndex,
  } = useCombobox({
    items: autocompleteSuggestions,
    onInputValueChange: ({inputValue}) => {
      // omitted for brevity
    },
  });
  return (
    <>
      {/* The search box is omitted for brevity */}
      <ul
        {...getMenuProps({
          'aria-label': "Autocomplete suggestions",
          'aria-labelledby': null,
        })}
      >
        {autocompleteSuggestions.length > 0
          ? autocompleteSuggestions.map((suggestion, index) => {
              return (
                <li
                  data-highlighted={index === highlightedIndex}
                  key={`suggestion-${index}`}
                  {...getItemProps({
                    suggestion,
                    index,
                    // ADDED FROM HERE
                    onClick: event => {
                      // Insert the code for showing the selected place on the map
                    },
                    // ADDED UNIL HERE
                  })}
                >
                  {suggestion}
                </li>
              );
            }) 
          : null}
      </ul>
    </>
  )
};
```
## 4. Demo
Here is [the CodeSandbox demo for the entire code written in this article](https://codesandbox.io/s/day-24-y4h4h2?file=/src/components/SearchBox.js).

## 5. Next up
In the next post of this blog series, I will use the code written in this article but replace the `mockAutocompleteSearch` function with the one to make a request to Google Maps API so that I can obtain real autocomplete suggestions in response to the user's search text.

Watch this space!

## Changelog

Oct 9, 2023 (v1.0.1): Fix typo in Section 1.

## References
Holachek, Alex (undated) “[Build a Better Mobile Input](https://better-mobile-inputs.netlify.app/)”, undated.

Johnson, Maisie (2019) “[3 ways to autofocus an input in React that ALMOST always work!](https://blog.maisie.ink/react-ref-autofocus)”, _blog.maisie.ink_, Oct 25, 2019.

Oliff, Christian (2019) “[Everything You Ever Wanted to Know About inputmode](https://css-tricks.com/everything-you-ever-wanted-to-know-about-inputmode/)”, _CSS-Tricks_, May 17, 2019.