How to make a list with a search field so the user can filter the list.
Demo
This is what we’re building:
- foo
- fooz
- bar
- baz
- quix
The React component
Here’s code for that example:
import type { ChangeEvent, ComponentProps } from 'react'
import { useState } from 'react'
const items = ['foo', 'fooz', 'bar', 'baz', 'quix']
export function FilterableList({ style, ...props }: ComponentProps<'div'>) {
const [searchResults, setSearchResults] = useState(items)
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
const value = event.target.value.toLowerCase()
if (value) {
const results = items.filter(item => item.toLowerCase().includes(value))
setSearchResults(results.length > 0 || value ? results : items)
} else {
setSearchResults(items)
}
}
return (
<div
{...props}
style={{
border: '1px solid #ddd',
padding: '20px 20px 10px 20px',
...style,
}}
>
<input
aria-controls='tag-list'
onChange={handleChange}
placeholder='Search'
style={{ padding: '5px 10px', marginBottom: '10px', ...style }}
type='text'
/>
<ul aria-live='polite' id='tag-list' role='region'>
{searchResults.length === 0 ? (
<li>No results</li>
) : (
searchResults.map(item => <li key={item}>{item}</li>)
)}
</ul>
</div>
)
}Accessibility
We need to tell screen readers to announce the changes that have happened on the page when filtering. This can be done by defining the list as an ARIA live region, see the highlighted lines and the explanation below:
<>
<input
aria-controls='tag-list'
aria-label='search'
onChange={handleChange}
placeholder='Search'
style={{ padding: '5px 10px', marginBottom: '10px', ...style }}
type='text'
/>
<ul aria-live='polite' id='tag-list' role='region'>
{searchResults.length === 0 ? (
<li>No results</li>
) : (
searchResults.map(item => <li key={item}>{item}</li>)
)}
</ul>
</>- aria-controls="tag-list"
This attribute tells the screen reader that this field controls the list below with the id of
tag-list.- aria-label="search"
We don’t have a label on the form field, so we can label it like this.
- aria-live="polite"
This marks the element as a live region, meaning it might update dynamically. The value of the attribute defines how the changes to the
tag-listare announced. Other values can beassertiveoroff.- role="region"
The region role is used to identify document areas the author deems significant. It is a generic landmark available to aid in navigation when none of the other landmark roles are appropriate.
Read more about regions
.