Обратная совместимость

Библиотека Focus-trap предназначена для управления фокусом внутри определённого контейнера. Основная задача — ограничение навигации по элементам интерфейса только элементами, находящимися внутри контейнера, что особенно важно для модальных окон, всплывающих подсказок и других интерактивных компонентов.

Основные принципы работы:

  • Фокус может перемещаться только между элементами внутри контейнера.
  • При попытке покинуть контейнер с помощью клавиши Tab фокус возвращается к первому или последнему элементу внутри.
  • Focus-trap автоматически сохраняет предыдущий фокус и возвращает его при деактивации.

Инициализация и базовые методы

Для создания трепа используется функция createFocusTrap:

import { createFocusTrap } from 'focus-trap';

const modal = document.getElementById('modal');
const focusTrap = createFocusTrap(modal, {
  escapeDeactivates: true,
  clickOutsideDeactivates: true,
  initialFocus: '#first-input'
});

// Активировать фокус
focusTrap.activate();

// Деактивировать фокус
focusTrap.deactivate();

Ключевые параметры:

  • escapeDeactivates — позволяет закрывать треп нажатием Escape.
  • clickOutsideDeactivates — клик вне контейнера деактивирует треп.
  • initialFocus — задаёт элемент, на который будет установлен фокус при активации.

Управление обратной совместимостью

Focus-trap развивается с учётом современных стандартов браузеров, но часто требуется поддержка старых версий, где focusin и focusout могут работать некорректно.

Поддержка старых браузеров обеспечивается через следующие механизмы:

  1. Fallback на setTimeout и document.activeElement — если событие focusin не поддерживается, библиотека проверяет активный элемент через таймер.
  2. Поллифиллы для Element.matches и Node.contains — используются для корректного определения, находится ли элемент внутри контейнера.
  3. Обход ограничения tabindex — старые браузеры могут неправильно обрабатывать tabindex="-1", поэтому Focus-trap временно изменяет его на допустимое значение при активации.

Пример включения трепа с учётом обратной совместимости:

const focusTrap = createFocusTrap(modal, {
  fallbackFocus: modal,
  returnFocusOnDeactivate: true,
  escapeDeactivates: true
});
  • fallbackFocus гарантирует, что даже если initialFocus не найден, фокус попадёт на контейнер.
  • returnFocusOnDeactivate обеспечивает возврат к элементу, который был активен до активации трепа.

Особенности старых браузеров

В Internet Explorer 11 и ранних версиях Edge существуют специфические нюансы:

  • Отсутствие поддержки focusin на Shadow DOM — библиотека создаёт дополнительный слушатель на корневом документе.
  • Некорректная обработка clickOutsideDeactivates — добавляется ручная проверка координат клика.
  • Табуляция в contenteditable — Focus-trap игнорирует элементы с contenteditable по умолчанию, чтобы избежать неожиданных переходов.

Конфигурация для сложных интерфейсов

Для интерфейсов с несколькими вложенными модальными окнами или панелями используется allowOutsideClick и динамическое управление activeTrap:

const outerTrap = createFocusTrap(outerModal);
const innerTrap = createFocusTrap(innerModal, {
  onActivate: () => outerTrap.pause(),
  onDeactivate: () => outerTrap.unpause()
});
  • pause() временно приостанавливает внешний треп, позволяя внутреннему управлять фокусом.
  • unpause() возвращает контроль внешнему трепу.

Интеграция с фреймворками

Focus-trap поддерживает прямую интеграцию с популярными библиотеками:

  • React — через focus-trap-react, создаются обёртки компонентов, автоматически активирующие треп.
  • Vue — через кастомные директивы, которые активируют и деактивируют треп при монтировании и размонтировании компонента.
  • Angular — через сервисы и хуки жизненного цикла, обеспечивается автоматический возврат фокуса.

Практические рекомендации

  1. Всегда задавать fallbackFocus для совместимости с браузерами, где initialFocus может не работать.
  2. Использовать returnFocusOnDeactivate для сохранения UX при закрытии модального окна.
  3. Для сложных интерфейсов с вложенными трепами применять методы pause() и unpause().
  4. Проверять совместимость с IE11 и старыми Edge, если продукт рассчитан на корпоративный сегмент.

Focus-trap обеспечивает надёжное управление фокусом даже в условиях ограниченной поддержки современных стандартов, позволяя создавать доступные и предсказуемые интерфейсы.