Программное управление фокусом внутри trap

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

Ключевые моменты:

  • Контейнер — элемент DOM, внутри которого будет работать trap.
  • Фокус цикличен: при попытке перемещения фокуса за пределы контейнера он возвращается к первому или последнему фокусируемому элементу.
  • Поддержка различных типов элементов: кнопки, ссылки, поля ввода, элементы с tabindex.

Установка и подключение

Для использования Focus-trap доступна установка через npm:

npm install focus-trap

Подключение в проект:

import { createFocusTrap } from 'focus-trap';

Создание и инициализация trap

Для создания trap используется функция createFocusTrap, которой передаётся контейнер и объект конфигурации:

const modal = document.getElementById('modal');

const trap = createFocusTrap(modal, {
  escapeDeactivates: true,
  clickOutsideDeactivates: false,
  allowOutsideClick: true,
  initialFocus: '#first-input',
  fallbackFocus: modal,
});

Пояснения ключевых опций:

  • escapeDeactivates — деактивирует trap при нажатии Esc.
  • clickOutsideDeactivates — деактивирует trap при клике вне контейнера.
  • allowOutsideClick — разрешает клики вне контейнера без деактивации.
  • initialFocus — элемент, который получает фокус при активации trap.
  • fallbackFocus — элемент, на который возвращается фокус, если указанный initialFocus недоступен.

Активация и деактивация trap

Trap не активен по умолчанию. Для активации используется метод activate(), для деактивации — deactivate().

// Активация при открытии модального окна
trap.activate();

// Деактивация при закрытии
trap.deactivate();

Можно также передавать колбэки, чтобы реагировать на события активации и деактивации:

const trap = createFocusTrap(modal, {
  onActivate: () => console.log('Trap активирован'),
  onDeactivate: () => console.log('Trap деактивирован'),
});

Управление фокусом внутри trap

Focus-trap автоматически определяет все фокусируемые элементы внутри контейнера:

  • <a href>
  • <button>
  • <input>, <textarea>, <select>
  • Элементы с положительным tabindex

Фокус при навигации с клавиатуры (Tab и Shift+Tab) перемещается циклично по этим элементам.

Для динамических контейнеров можно использовать метод updateTabbables(), чтобы пересчитать фокусируемые элементы:

trap.updateTabbables();

Это особенно важно, если внутри модального окна добавляются новые интерактивные элементы после инициализации trap.

Поддержка клавиатурных событий

Trap корректно обрабатывает нажатия клавиш:

  • Tab — перемещение фокуса вперёд.
  • Shift + Tab — перемещение фокуса назад.
  • Esc — деактивация trap (если включено escapeDeactivates).

Можно настроить кастомное поведение при этих событиях с помощью onKeydown:

const trap = createFocusTrap(modal, {
  onKeydown: (e) => {
    if (e.key === 'Enter') {
      console.log('Enter внутри trap');
    }
  },
});

Управление несколькими trap

При наличии нескольких интерактивных элементов на странице можно создавать несколько trap, но рекомендуется активировать только один в каждый момент времени. Конфликты решаются через:

  • Деактивацию предыдущего trap перед активацией нового.
  • Использование returnFocusOnDeactivate для возврата фокуса к исходному элементу.
trap.activate();
// Работа с другим модальным окном
secondTrap.activate();
trap.deactivate(); // возвращает фокус к исходному элементу

Настройка фокусируемого элемента по умолчанию

Опция initialFocus позволяет точно задать, какой элемент будет выбран при активации trap:

initialFocus: '#username-input'

Если элемент отсутствует или не фокусируемый, используется fallbackFocus. Это предотвращает потерю фокуса и гарантирует корректную работу с клавиатурой.

Работа с асинхронным контентом

При динамическом добавлении контента (например, через AJAX или React-компоненты) trap может активироваться до появления всех интерактивных элементов. В этом случае рекомендуется:

  1. Вызывать updateTabbables() после добавления новых элементов.
  2. Устанавливать initialFocus на существующий элемент или использовать fallbackFocus.
  3. Обновлять trap перед каждым открытием модального окна, если структура контента меняется.

Особенности использования в SPA

В одностраничных приложениях (SPA) trap помогает управлять фокусом при навигации между модальными окнами или интерактивными компонентами. Важно:

  • Всегда деактивировать trap при уходе со страницы или закрытии компонента.
  • Использовать returnFocusOnDeactivate, чтобы пользователь вернулся к предыдущему элементу после закрытия модального окна.
  • Контролировать порядок tabindex для логической последовательности элементов.

Практические советы

  • Всегда указывать initialFocus, чтобы избежать непредсказуемого поведения.
  • Для модальных окон использовать clickOutsideDeactivates: false, чтобы не закрывать окно случайным кликом.
  • Проверять поддержку всех фокусируемых элементов, особенно кастомных кнопок и интерактивных элементов без стандартного tabindex.
  • Для динамических элементов пересчитывать tabbables после их добавления или удаления.

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