souporserious

Build a ComboBox Component with useId

2 min read

React 18 brings us a new useId hook that will be useful for accessibility. In this post, we build a ComboBox component and learn how to take advantage of this new hook.

Today, we’ll learn how the seemingly subtle useId hook coming to React 18 can significantly help screen readers and ensure proper accessibility for your applications. A combo box is one of those components you hope you never have to make and instead wish the platform offered a solution for. By the end of this article, we’ll have a combo box component to help users autocomplete a list of results. Let’s get started!

First, we’ll reference the wai-aria examples for combo box. To keep things simple, we’ll duplicate the first example in React. We’ll start by creating a custom ComboBox component and render an input with the attributes mentioned in the spec. A combo box requires proper context, which today will be showing a list of results that users can manually choose to autocomplete their favorite fruit.

1function ComboBox() {
2 return <input aria-autocomplete="list" />
3}

We then add our list where we’ll render results using the children prop, which offers a better experience for user’s to compose options similar to how the native select element works:

1function ComboBox({ children, value }) {
2 return (
3 <>
4 <input aria-autocomplete="list" value={value} />
5 <ul role="listbox">{children}</ul>
6 </>
7 )
8}
1import { useId } from 'react'
2
3function ComboBox({ children, value }) {
4 const id = useId()
5 return (
6 <>
7 <input aria-autocomplete="list" aria-controls={id} value={value} />
8 <ul role="listbox" id={id}>
9 {children}
10 </ul>
11 </>
12 )
13}

Next, we need to implement a Result component library users can provide for the results. The spec requires using a unique identifier for aria-activedescendant. We can again utilize useId to generate an id for each list item we can target.

1import { useId } from 'react'
2
3function Result({ value }) {
4 const id = useId()
5 return (
6 <li id={id} role="option">
7 {value}
8 </li>
9 )
10}
Updated:
  • javascript
  • documentation
  • jsdoc
© 2022 Travis Arnold