Библиотека Tabbable предназначена для определения элементов на веб-странице, которые могут получать фокус с помощью клавиши Tab. Она используется для улучшения навигации и обеспечения доступности интерфейсов, особенно в сложных компонентах, таких как модальные окна, табы и динамические панели.
Основной экспорт библиотеки — функция
tabbable(node, options), которая возвращает массив
элементов, доступных для фокусировки в пределах указанного DOM-узла.
Каждый элемент в этом массиве соответствует элементу, на который можно
перейти с помощью клавиши Tab, учитывая состояние disabled,
visibility и tabindex.
import { tabbable } from 'tabbable';
const focusableElements = tabbable(document.body);
console.log(focusableElements);
Функция возвращает только видимые и активные
элементы, автоматически исключая те, которые скрыты с помощью
display: none, visibility: hidden, или имеют
отрицательный tabindex, за исключением опции
includeGuard, о которой речь далее.
Функция tabbable поддерживает объект опций:
true,
возвращает контейнер вместе с его фокусируемыми потомками, если он сам
является фокусируемым элементом.true. Если установить false, будут включены
элементы с отрицательным tabindex.Пример использования с опциями:
const focusableElements = tabbable(document.querySelector('#modal'), {
includeContainer: true,
includeOnlyTabbable: true
});
В интерфейсах с динамическими кнопками, например, каруселями или пагинацией, важно правильно управлять порядком табуляции. С библиотекой Tabbable это достигается с помощью фильтрации элементов:
const navigationContainer = document.querySelector('.pagination');
const buttons = tabbable(navigationContainer);
// Перевод фокуса на первую кнопку при открытии страницы
if (buttons.length > 0) {
buttons[0].focus();
}
// Обработка стрелок для переключения кнопок
navigationContainer.addEventListener('keydown', (e) => {
const currentIndex = buttons.indexOf(document.activeElement);
if (e.key === 'ArrowRight' && currentIndex < buttons.length - 1) {
buttons[currentIndex + 1].focus();
} else if (e.key === 'ArrowLeft' && currentIndex > 0) {
buttons[currentIndex - 1].focus();
}
});
Такой подход гарантирует, что при динамическом изменении контента (например, при добавлении новых страниц) порядок фокуса остаётся корректным и соответствует ожиданиям пользователей клавиатуры.
В сложных интерфейсах элементы кнопок могут находиться внутри Shadow
DOM. Библиотека Tabbable поддерживает обход таких
структур через опцию getShadowRoot:
const focusableInShadow = tabbable(document.querySelector('#component'), {
getShadowRoot: node => node.shadowRoot
});
Это позволяет создавать полностью фокусируемые интерфейсы даже при использовании Web Components.
В модальных диалогах и панелях с кнопками навигации важно не допускать выхода фокуса за пределы компонента. Для этого используются элементы-сторожи:
const modal = document.querySelector('#modal');
const firstFocusable = tabbable(modal)[0];
const lastFocusable = tabbable(modal).slice(-1)[0];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
} else if (!e.shiftKey && document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
});
Такой паттерн обеспечивает циклическую навигацию, что является стандартом доступности.
tabindex допускается только
для элементов, которые не должны попадать в порядок табуляции по
умолчанию.Библиотека Tabbable предоставляет строгий и предсказуемый контроль над фокусируемыми элементами, позволяя:
Эти возможности делают Tabbable ключевым инструментом для разработки доступных интерфейсов с динамическими кнопками навигации и сложными UI-компонентами.