Floating UI предоставляет расширенные возможности для позиционирования всплывающих элементов, таких как тултипы, модальные окна, меню и панели. Одним из ключевых аспектов интерактивности является поддержка управления с клавиатуры, что критично для доступности (accessibility) и удобства использования.
Для корректной работы с клавиатурой необходимо правильно
управлять фокусом. Floating UI позволяет отслеживать и
управлять фокусируемыми элементами внутри всплывающего окна через
утилиты, такие как focusManager.
Floating UI не навязывает конкретный способ обработки клавиш, но предоставляет инструменты для создания гибких решений:
Пример обработки клавиш в контексте Floating UI:
function handleKeyDown(event, floatingElement) {
switch(event.key) {
case 'Escape':
closeFloating(floatingElement);
break;
case 'ArrowDown':
focusNextItem(floatingElement);
break;
case 'ArrowUp':
focusPrevItem(floatingElement);
break;
case 'Tab':
trapFocus(event, floatingElement);
break;
}
}
Floating UI интегрируется с концепцией focus trapping, когда пользователь не может случайно выйти из модального окна с помощью Tab. Реализация включает:
function trapFocus(event, floatingElement) {
const focusableElements = floatingElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
} else if (!event.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
Для удобства навигации часто используют middleware Floating UI, которые управляют позиционированием и состоянием элементов. Некоторые полезные middleware:
Эти middleware помогают поддерживать правильное отображение элементов при работе с клавиатурой, особенно при перемещении фокуса между элементами.
Для корректной работы с клавиатурой крайне важно использовать ARIA-атрибуты:
aria-haspopup – указывает, что элемент открывает
всплывающее окно.aria-expanded – отражает состояние
(открыто/закрыто).role="menu" и role="menuitem" – для
контекстных меню.aria-activedescendant – указывает на текущий выбранный
элемент при навигации стрелками.Пример использования ARIA с меню:
<button id="menuButton" aria-haspopup="true" aria-expanded="false">Меню</button>
<ul role="menu" id="menuList">
<li role="menuitem" tabindex="-1">Элемент 1</li>
<li role="menuitem" tabindex="-1">Элемент 2</li>
<li role="menuitem" tabindex="-1">Элемент 3</li>
</ul>
keydown на уровне документа или
родительского контейнера для предотвращения конфликтов с другими
обработчиками.Комбинируя autoUpdate, offset и focus
trapping, можно реализовать всплывающее меню, которое:
import { computePosition, offset, flip, autoUpdate } from '@floating-ui/dom';
const button = document.querySelector('#menuButton');
const menu = document.querySelector('#menuList');
button.addEventListener('click', () => {
menu.style.display = 'block';
menu.querySelector('[role="menuitem"]').focus();
const cleanup = autoUpdate(button, menu, () => {
computePosition(button, menu, { middleware: [offset(4), flip()] })
.then(({ x, y }) => {
Object.assign(menu.style, { left: `${x}px`, top: `${y}px` });
});
});
function closeMenu() {
menu.style.display = 'none';
button.focus();
cleanup();
}
menu.addEventListener('keydown', (e) => handleKeyDown(e, menu, closeMenu));
});
В результате управление с клавиатуры становится полноценным и предсказуемым, а Floating UI обеспечивает стабильное позиционирование и поддержку сложных интерактивных элементов.