Переиспользование экземпляров

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

Основной объект — это трап-фокус (focus trap), который создается для конкретного DOM-элемента и управляет циклическим перемещением фокуса между интерактивными элементами внутри этого элемента.

Создание и инициализация трапа

import { createFocusTrap } from 'focus-trap';

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

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

Ключевые опции:

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

Переиспользование экземпляров

Создание нового трапа каждый раз при открытии модального окна может приводить к лишним расходам памяти и усложнять управление состояниями. Переиспользование экземпляров позволяет создавать трап один раз и активировать его многократно.

Пример повторного использования

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

function openModal() {
  modal.style.display = 'block';
  focusTrap.activate();
}

function closeModal() {
  focusTrap.deactivate();
  modal.style.display = 'none';
}

В данном случае один экземпляр focusTrap используется каждый раз при открытии модального окна. Деактивация освобождает управление фокусом, но сам объект остаётся доступным для повторной активации.

Динамическое обновление фокуса

При переиспользовании экземпляров важно управлять динамическими элементами внутри контейнера. Если интерактивные элементы добавляются или удаляются, трап автоматически корректирует порядок фокуса, но можно задать новый initialFocus при активации:

function openModalWithDynamicFocus(selector) {
  focusTrap.setInitialFocus(selector);
  focusTrap.activate();
}

Метод setInitialFocus позволяет изменить элемент, на который будет установлен фокус, без создания нового экземпляра трапа.

Обработка нескольких модальных окон

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

const modalA = createFocusTrap(document.getElementById('modalA'));
const modalB = createFocusTrap(document.getElementById('modalB'));

function openModalA() {
  modalB.deactivate();
  modalA.activate();
}

function openModalB() {
  modalA.deactivate();
  modalB.activate();
}

Вариант с переиспользованием одного трапа на разные контейнеры возможен, но требует корректной перенастройки container:

focusTrap.updateContainer(newContainer);
focusTrap.activate();

Дополнительные возможности при переиспользовании

  • Промежуточные обработчики событий: при повторной активации можно добавлять функции onActivate и onDeactivate, чтобы выполнять определённые действия без создания нового экземпляра.
  • Сохранение состояния фокуса: деактивация не стирает внутренние настройки трапа, что позволяет возобновлять работу с того же состояния.
  • Интеграция с библиотеками управления состоянием: Focus-trap можно комбинировать с Redux, Vuex или другими менеджерами состояния, передавая управление через store без повторного создания экземпляров.

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

  • Один экземпляр на один контейнер оптимален для повторного открытия и закрытия модальных окон.
  • Для интерфейсов с динамическими контейнерами можно использовать методы updateContainer и setInitialFocus.
  • Всегда деактивировать трап при скрытии элемента, чтобы не блокировать фокус на невидимых компонентах.
  • Использование onActivate и onDeactivate упрощает интеграцию с анимациями и сторонними библиотеками.

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