Одной из частых ошибок является некорректное указание элемента, внутри которого должен работать focus-trap. Библиотека ожидает DOM-элемент, а не селектор в виде строки. Пример неверного использования:
import createFocusTrap from 'focus-trap';
const trap = createFocusTrap('#modal'); // ❌ передаём строку вместо DOM-элемента
Правильный вариант:
const modalElement = document.getElementById('modal');
const trap = createFocusTrap(modalElement); // ✅ передаём DOM-элемент
Передача строки может привести к ошибкам времени выполнения или к тому, что фокус не будет корректно ограничен.
Focus-trap создаёт контейнер, но не активирует его
автоматически. Часто разработчики создают trap и забывают
вызвать метод activate():
const trap = createFocusTrap(modalElement);
// trap.activate(); ❌ забыли вызвать
Это приводит к тому, что фокус всё ещё может покидать модальное окно или диалог. Всегда важно вызывать методы:
trap.activate(); // ✅ активируем фокус-трап
trap.deactivate(); // ✅ при закрытии модального окна
Focus-trap фиксирует фокус на элементах, доступных в момент активации. Если внутри контейнера добавляются новые фокусируемые элементы после активации, они могут быть недоступны для навигации через Tab.
Ошибка:
trap.activate();
modalElement.innerHTML += '<button id="new-btn">Новая кнопка</button>';
Решение — деактивировать и заново активировать trap после изменения DOM:
trap.deactivate();
trap.activate();
Или использовать опцию allowOutsideClick совместно с
динамическим управлением:
const trap = createFocusTrap(modalElement, {
allowOutsideClick: true
});
Focus-trap предоставляет множество опций, таких как
initialFocus, fallbackFocus,
clickOutsideDeactivates, escapeDeactivates.
Ошибки в их применении приводят к неожиданному поведению:
initialFocus — часто указывают
селектор, который отсутствует в DOM на момент активации. В результате
фокус может установиться на первый фокусируемый элемент контейнера по
умолчанию.fallbackFocus — используется как
запасной элемент, если initialFocus недоступен.
Неправильное указание или отсутствие fallback может заблокировать
фокус.clickOutsideDeactivates — если не
установить явно, клик вне контейнера не завершает trap, что иногда
противоречит UX.Пример правильного задания опций:
const trap = createFocusTrap(modalElement, {
initialFocus: '#first-input',
fallbackFocus: modalElement,
escapeDeactivates: true,
clickOutsideDeactivates: true
});
Focus-trap не проверяет CSS-свойства, такие как
display: none или visibility: hidden. Если
активировать trap на скрытом элементе, фокус будет непредсказуемо
установлен:
modalElement.style.display = 'none';
trap.activate(); // ❌ фокус не установится корректно
Рекомендуется активировать trap только после того, как элемент стал видимым:
modalElement.style.display = 'block';
trap.activate(); // ✅ безопасная активация
Использование нескольких библиотек, которые управляют фокусом, может
приводить к конфликтам. Например, одновременная работа
focus-trap и кастомных обработчиков на keydown
для Tab:
modalElement.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
// собственная логика
}
});
trap.activate();
В результате фокус может “застревать” вне контейнера или прыгать непредсказуемо. Лучший подход — полагаться на встроенные возможности focus-trap и избегать ручной перехватки Tab внутри контейнера.
Focus-trap поддерживает опцию возврата фокуса на элемент, который был
активен перед активацией trap (returnFocusOnDeactivate).
Если не включить эту опцию, пользовательский фокус может потеряться
после закрытия модального окна:
const trap = createFocusTrap(modalElement, {
returnFocusOnDeactivate: true
});
Без этой настройки фокус останется либо на body, либо на последнем фокусируемом элементе, что нарушает удобство навигации.
Модальные окна или панели часто открываются асинхронно, например, после загрузки данных с сервера. Если активировать trap до того, как элемент реально появится в DOM, focus-trap не сможет корректно установить фокус:
fetch('/modal-content').then(() => {
trap.activate(); // ❌ элемент может быть ещё не вставлен
});
Правильный подход — запускать activate() после полной
вставки содержимого в DOM:
fetch('/modal-content').then((html) => {
modalElement.innerHTML = html;
trap.activate(); // ✅ теперь элемент доступен
});
Эти ошибки встречаются наиболее часто при работе с focus-trap и могут нарушать доступность и UX веб-приложений. Их систематическое понимание и правильная настройка позволяют создавать безопасные и предсказуемые модальные интерфейсы.