Примеры практического применения

Библиотека Tabbable в JavaScript предназначена для определения фокусуируемых элементов на веб-странице, то есть элементов, на которые пользователь может переместить фокус с помощью клавиши Tab. Она работает как с элементами по умолчанию фокусируемыми (input, button, a[href]), так и с элементами, у которых явно задан атрибут tabindex.

Методы библиотеки позволяют:

  • Получить список всех фокусируемых элементов внутри контейнера.
  • Определить, какие из элементов могут быть активны для навигации клавишами.
  • Игнорировать скрытые или недоступные элементы.

Основные функции

  1. tabbable(container, options) Возвращает массив элементов внутри контейнера, которые можно фокусировать. Параметры:

    • container — DOM-элемент или документ.

    • options (необязательный объект):

      • includeContainer — включать ли сам контейнер, если он фокусируемый.
      • getShadowRoot — функция для обхода shadow DOM.

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

import { tabbable } from 'tabbable';

const container = document.querySelector('#form');
const focusableElements = tabbable(container);

console.log(focusableElements); 
// Выведет массив элементов, доступных для Tab
  1. isTabbable(element, options) Проверяет, может ли конкретный элемент быть фокусируемым при навигации Tab. Возвращает true или false.
import { isTabbable } from 'tabbable';

const button = document.querySelector('#submit');
if (isTabbable(button)) {
  button.focus();
}
  1. focusable(element, options) Определяет, является ли элемент фокусируемым, независимо от того, находится ли он в порядке табуляции.

Работа с shadow DOM и скрытыми элементами

Tabbable корректно обрабатывает shadow DOM, что важно при использовании веб-компонентов. Для этого можно использовать опцию getShadowRoot:

const focusableInShadow = tabbable(container, {
  getShadowRoot: (node) => node.shadowRoot
});

Скрытые элементы (display: none или visibility: hidden) и элементы с атрибутом disabled автоматически исключаются из списка. Это позволяет строить динамические формы и диалоги без необходимости вручную фильтровать недоступные элементы.

Практические примеры применения

Управление модальными окнами

При создании модальных окон важно замкнуть фокус внутри модального контейнера. Использование tabbable позволяет определить первый и последний фокусируемые элементы и реализовать циклический Tab:

const modal = document.querySelector('.modal');
const focusableEls = tabbable(modal);
const firstEl = focusableEls[0];
const lastEl = focusableEls[focusableEls.length - 1];

modal.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    if (e.shiftKey && document.activeElement === firstEl) {
      e.preventDefault();
      lastEl.focus();
    } else if (!e.shiftKey && document.activeElement === lastEl) {
      e.preventDefault();
      firstEl.focus();
    }
  }
});

Динамические формы

В формах, где элементы создаются или удаляются динамически, tabbable позволяет обновлять порядок навигации без ручного контроля tabindex:

const formContainer = document.querySelector('#dynamicForm');

function updateFocusable() {
  const focusableEls = tabbable(formContainer);
  console.log('Доступные для Tab элементы:', focusableEls);
}

Специальные компоненты интерфейса

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

  • Игнорировать невидимые панели.
  • Поддерживать корректный порядок Tab внутри сложных компонентов.
  • Сохранять совместимость с aria-hidden и другими атрибутами доступности.

Настройка порядка фокуса

Хотя Tabbable учитывает tabindex, для сложных интерфейсов иногда нужно комбинировать его с пользовательской логикой:

const focusableEls = tabbable(container).sort((a, b) => {
  return (a.tabIndex || 0) - (b.tabIndex || 0);
});

Это позволяет гибко управлять навигацией, например, помещая кнопки действий в конец списка, но оставляя их доступными для клавиатуры.

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

В React, Vue или Svelte библиотека легко интегрируется через хуки или lifecycle-методы:

useEffect(() => {
  const focusableEls = tabbable(containerRef.current);
  focusableEls[0].focus();
}, [containerRef]);

Такой подход упрощает работу с динамическими компонентами и улучшает доступность приложений.

Обработка особых случаев

  • Disabled элементы исключаются автоматически.
  • Elements with aria-hidden="true" не включаются в список.
  • Элементы с tabindex="-1" доступны только через метод focusable, но не через tabbable.

Это позволяет точно контролировать, какие элементы доступны для клавиатурной навигации, а какие — только программно.

Использование библиотеки Tabbable обеспечивает корректное управление фокусом, улучшает доступность интерфейсов и упрощает работу с динамическими компонентами в современных веб-приложениях.