useCombobox

Build a keyboard-navigable autocomplete or combobox easily.

Features

  • Fully controlled input
  • Keyboard arrow navigation
  • Highlighted index handling

Usage

1const {
2  query, setQuery, filtered,
3  highlightedIndex, handleKeyDown
4} = useCombobox(countries, c => c.name)
5
6<input
7  value={query}
8  onChange={e => setQuery(e.target.value)}
9  onKeyDown={handleKeyDown}
10/>
11
12<ul>
13  {filtered.map((c, i) => (
14    <li key={c.code} className={i === highlightedIndex ? 'bg-gray-200' : ''}>
15      {c.name}
16    </li>
17  ))}
18</ul>

📋 Source Code

This is the full implementation of useCombobox

1import { useState } from 'react'
2
3export function useCombobox<T>(items: T[], keyFn: (item: T) => string) {
4  const [query, setQuery] = useState('')
5  const [highlightedIndex, setHighlightedIndex] = useState(0)
6
7  const filtered = items.filter(item => keyFn(item).toLowerCase().includes(query.toLowerCase()))
8
9  const select = () => filtered[highlightedIndex]
10
11  const handleKeyDown = (e: React.KeyboardEvent) => {
12    if (e.key === 'ArrowDown') {
13      setHighlightedIndex(i => (i + 1) % filtered.length)
14    } else if (e.key === 'ArrowUp') {
15      setHighlightedIndex(i => (i - 1 + filtered.length) % filtered.length)
16    }
17  }
18
19  return {
20    query,
21    setQuery,
22    highlightedIndex,
23    filtered,
24    handleKeyDown,
25    select,
26  }
27}
28