Tabbable — это легковесная библиотека JavaScript,
предназначенная для определения элементов на веб-странице, доступных для
навигации с клавиатуры с помощью клавиши Tab. Основная
цель библиотеки — упрощение управления фокусом, особенно в динамических
интерфейсах, где элементы могут появляться, исчезать или изменять своё
состояние. Она не управляет самим фокусом, но предоставляет корректный и
стандартизированный способ его отслеживания.
Ключевые моменты работы библиотеки:
Tabbable учитывает все HTML-атрибуты, влияющие на фокус:
tabindex, disabled, aria-hidden,
hidden.tabindex ≥ 0.Установка через npm:
npm install tabbable
Подключение в проект:
import { tabbable, isTabbable } from 'tabbable';
tabbable(element) возвращает массив всех фокусируемых
элементов внутри контейнера element. Функция
isTabbable(element) проверяет, можно ли установить фокус на
конкретный элемент.
Для управления фокусом важно получить список всех элементов, доступных для табуляции. Это делается так:
const container = document.querySelector('.slide');
const focusableElements = tabbable(container);
Особенности фильтрации:
display: none или
visibility: hidden исключаются.disabled или aria-hidden="true"
игнорируются.tabindex="-1" не включаются в список, но
остаются доступными для программного фокуса.Для управления фокусом между слайдами, важно правильно определять первый и последний фокусируемый элемент в контейнере. Это позволяет реализовать замкнутую навигацию:
function focusFirstElement(slide) {
const elements = tabbable(slide);
if (elements.length > 0) {
elements[0].focus();
}
}
function focusLastElement(slide) {
const elements = tabbable(slide);
if (elements.length > 0) {
elements[elements.length - 1].focus();
}
}
При использовании стрелок или Tab для перехода между слайдами можно программно переназначать фокус на первый элемент следующего слайда или на последний элемент предыдущего.
Для модальных окон или интерактивных слайдеров часто используют замкнутый фокус, когда клавиша Tab циклически проходит только по элементам текущего контейнера:
function trapFocus(slide) {
const elements = tabbable(slide);
const first = elements[0];
const last = elements[elements.length - 1];
slide.addEventListener('keydown', (event) => {
if (event.key === 'Tab') {
if (event.shiftKey) {
if (document.activeElement === first) {
last.focus();
event.preventDefault();
}
} else {
if (document.activeElement === last) {
first.focus();
event.preventDefault();
}
}
}
});
}
Эта техника гарантирует, что пользователь не покинет область слайдера при навигации клавишей Tab, что особенно важно для интерфейсов с динамическим содержимым.
Когда слайды динамически изменяются (например, добавляются новые элементы), важно обновлять список фокусируемых элементов каждый раз при изменении DOM:
function updateFocusableElements(slide) {
return tabbable(slide);
}
Это позволяет корректно обрабатывать появление новых кнопок, ссылок или полей ввода без нарушения последовательности табуляции.
tabbable() для больших
контейнеров. Лучше кешировать результат и обновлять только при изменении
DOM.isTabbable() для проверки одиночных
элементов без перебора всех дочерних узлов.Tabbable легко интегрируется с React, Vue или Angular. В
React можно использовать эффект для обновления списка фокусируемых
элементов при монтировании или изменении слайда:
import { useEffect, useRef } from 'react';
import { tabbable } from 'tabbable';
function Slide({ children }) {
const slideRef = useRef(null);
useEffect(() => {
const elements = tabbable(slideRef.current);
if (elements.length > 0) {
elements[0].focus();
}
}, [children]);
return <div ref={slideRef}>{children}</div>;
}
Таким образом обеспечивается автоматическое управление фокусом при смене слайда и динамическом контенте.
tabindextabindex="0" — элемент включается в
обычную последовательность Tab.tabindex="-1" — элемент можно
фокусировать программно, но он исключён из последовательности Tab.tabindex>0 — элемент получает
приоритет при табуляции перед элементами с tabindex="0";
использовать следует осторожно, чтобы не нарушать естественный порядок
фокуса.Библиотека Tabbable обеспечивает надежное определение
всех интерактивных элементов, учитывает стандартные атрибуты доступности
и позволяет реализовать корректную, предсказуемую навигацию клавиатурой
даже в сложных интерфейсах с динамическим содержимым.