Компоненты autocomplete и combobox относятся к категории интерактивных элементов ввода, которые объединяют текстовое поле и выпадающий список вариантов. Основная задача — ускорение ввода и снижение количества ошибок за счёт динамических подсказок.
В терминах UI:
Библиотека Floating UI предоставляет низкоуровневые инструменты для позиционирования, управления взаимодействиями и доступности таких компонентов, не навязывая конкретную реализацию.
Реализация autocomplete/combobox строится из нескольких независимых частей:
Ключевой принцип — отделение логики позиционирования от логики взаимодействия.
Для создания выпадающего списка используется хук
useFloating:
import { useFloating, offset, flip, shift } from '@floating-ui/react';
const { refs, floatingStyles, context } = useFloating({
placement: 'bottom-start',
middleware: [
offset(4),
flip(),
shift()
]
});
refs.setReference — привязывается к inputrefs.setFloating — привязывается к спискуfloatingStyles — стили позиционированияСостояние открытия контролируется вручную:
const [open, setOpen] = useState(false);
Часто используется комбинация:
С помощью useInteractions:
import { useInteractions, useDismiss, useRole } from '@floating-ui/react';
const dismiss = useDismiss(context);
const role = useRole(context, { role: 'listbox' });
const { getReferenceProps, getFloatingProps } = useInteractions([
dismiss,
role
]);
Autocomplete предполагает динамическую фильтрацию данных:
const [query, setQuery] = useState('');
const filteredItems = items.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
);
Input связывается с состоянием:
<input
ref={refs.setReference}
value={query}
onCha nge={(e) => {
setQuery(e.target.value);
setOpen(true);
}}
/>
Floating UI предоставляет хук useListNavigation для
управления активным элементом:
import { useListNavigation } from '@floating-ui/react';
const listRef = useRef([]);
const [activeIndex, setActiveIndex] = useState(null);
const listNavigation = useListNavigation(context, {
listRef,
activeIndex,
onNavigate: setActiveIndex,
loop: true
});
Особенности:
loop позволяет зацикливать списокВыбор можно реализовать через клик или клавишу Enter:
const handleSelect = (index) => {
setQuery(filteredItems[index]);
setOpen(false);
};
Интеграция с клавиатурой:
import { useTypeahead } from '@floating-ui/react';
const typeahead = useTypeahead(context, {
listRef,
activeIndex,
onMatch: setActiveIndex
});
{open && (
<ul
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
>
{filteredItems.map((item, index) => (
<li
key={item}
ref={(node) => (listRef.current[index] = node)}
onCl ick={() => handleSelect(index)}
style={{
background: index === activeIndex ? '#eee' : 'white'
}}
>
{item}
</li>
))}
</ul>
)}
Combobox требует строгого соблюдения ARIA-спецификации:
<input
role="combobox"
aria-expanded={open}
aria-controls="listbox-id"
aria-autocomplete="list"
/>
<ul role="listbox">
<li role="option" aria-selected={active}>
Floating UI автоматически помогает с ролями через
useRole.
Для корректной работы клавиатуры используется
FloatingFocusManager:
import { FloatingFocusManager } from '@floating-ui/react';
{open && (
<FloatingFocusManager context={context} modal={false}>
<ul>...</ul>
</FloatingFocusManager>
)}
Особенности:
modal={false} — не блокирует остальной интерфейсuseDismiss автоматически закрывает список при клике
вне:
const dismiss = useDismiss(context, {
outsidePress: true
});
Дополнительно:
useEffect(() => {
if (!query) return;
fetch(`/api?q=${query}`)
.then(res => res.json())
.then(setItems);
}, [query]);
Важно учитывать:
При большом количестве элементов:
react-virtualAutocomplete не ограничен текстом:
<li>
<img src={avatar} />
<span>{name}</span>
</li>
Важно:
listRefCombobox может поддерживать multiple selection:
Ключевые моменты:
useMemo)React.memo для элементов1. Потеря фокуса при клике
mousedown или
FloatingFocusManager2. Некорректная навигация
listRefactiveIndex3. Проблемы с позиционированием
shift или flip| Характеристика | Autocomplete | Combobox |
|---|---|---|
| Свободный ввод | Да | Ограничен |
| Строгий выбор | Нет | Да |
| ARIA требования | Умеренные | Строгие |
| Использование | Поиск, фильтрация | Формы, селекты |
Combobox часто используется как замена
<select>:
Floating UI не ограничивает реализацию: