Библиотека Tabbable в JavaScript предназначена для определения элементов страницы, которые могут получать фокус с помощью клавиши Tab. Она упрощает работу с управлением фокусом в приложениях, обеспечивая корректное взаимодействие с пользователем и соблюдение стандартов ARIA. Основной функционал библиотеки заключается в поиске всех элементов, которые потенциально могут быть “фокусируемыми”, и предоставлении их в виде упорядоченного массива.
Элементы делятся на три категории:
Для работы с Tabbable используется стандартный npm-пакет:
npm install tabbable
Подключение в проект:
import { tabbable, focusable } from 'tabbable';
Функции возвращают массив DOM-элементов, упорядоченных в соответствии с их логическим порядком на странице.
tabbable(container, options)Возвращает массив элементов, доступных для навигации с клавиши Tab. Параметры:
container – DOM-элемент или документ, внутри
которого осуществляется поиск.
options – объект с настройками:
includeContainer – включить сам контейнер, если он
tabbable (по умолчанию false).getShadowRoot – функция, возвращающая shadow root для
обхода теневых DOM-деревьев.Пример:
const tabbableElements = tabbable(document.body);
tabbableElements.forEach(el => console.log(el.tagName));
focusable(container, options)Возвращает элементы, которые могут получить фокус программно, даже если они не включены в порядок табуляции. Позволяет гибко управлять доступностью элементов без изменения их видимости.
const focusableElements = focusable(document.body, { includeContainer: true });
Tabbable учитывает атрибуты ARIA для правильного определения фокусируемых элементов:
aria-hidden="true" – элементы игнорируются.role="presentation" или role="none" –
элементы не добавляются в порядок табуляции.tabindex="-1" – элемент focusable, но не tabbable.tabindex="0" – элемент tabbable и включен в стандартный
порядок.Это позволяет создавать интерфейсы, полностью соответствующие спецификации ARIA, включая корректное управление доступностью для экранных читалок.
button,
a[href], input, select,
textarea) по умолчанию считаются tabbable, если они не
disabled.contenteditable –
автоматически focusable.getShadowRoot библиотека рекурсивно обходит shadow DOM,
учитывая фокусируемые элементы внутри.Tabbable не поддерживает автоматическое отслеживание изменений DOM.
Для динамически добавляемых элементов необходимо повторно вызывать
функции tabbable или focusable после изменения
структуры страницы. Это обеспечивает актуальный порядок табуляции и
предотвращает проблемы с доступностью.
Для сложных компонентов, таких как модальные окна, всплывающие панели или кастомные виджеты:
tabbable и управления
программным фокусом через element.focus().const modal = document.querySelector('#modal');
const focusableElements = tabbable(modal);
let first = focusableElements[0];
let last = focusableElements[focusableElements.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
Этот подход обеспечивает циклическую навигацию по модальному окну, предотвращая выход фокуса за пределы компонента.
includeContainer и рекурсивного обхода
shadow DOM должно быть оправдано конкретной задачей, так как каждая
рекурсия увеличивает время выполнения.tabindex для интерактивных ячеек.tabindex и shadow DOM.tabbable отдельно.display: none,
visibility: hidden) игнорируются автоматически.