Библиотека Tabbable предназначена для определения
элементов на странице, которые могут получать фокус с помощью клавиши
Tab. Она решает задачу идентификации всех интерактивных элементов,
включая кнопки, ссылки, поля ввода, а также кастомные компоненты с
установленным tabindex. Основной принцип работы заключается
в фильтрации DOM-дерева для выделения элементов, доступных для навигации
клавиатурой.
Ключевые функции библиотеки:
tabbable(container) — возвращает массив всех элементов,
которые могут быть табулированы внутри указанного контейнера.isTabbable(element) — проверяет, может ли конкретный
элемент получить фокус через Tab.focusable(element) — определяет, можно ли программно
сфокусировать элемент (element.focus()), даже если он не
является частью последовательности табуляции.Элемент считается tabbable, если соблюдаются следующие условия:
Элемент видим (offsetParent не null,
display не none, visibility не
hidden).
Элемент не отключен (disabled отсутствует или
false).
Для элементов с tabindex:
tabindex="0" делает элемент частью естественной
последовательности табуляции.tabindex > 0 задаёт пользовательский порядок
навигации, но его использование не рекомендуется для сложных интерфейсов
из-за потенциальных проблем с предсказуемостью.tabindex < 0 исключает элемент из
последовательности, но оставляет его доступным для программного
фокуса.Элементы по умолчанию табулируемы:
<a> с атрибутом href<button>, <input>,
<textarea>, <select>tabindex ≥ 0Зоны сброса — это участки DOM, внутри которых можно ограничить фокусировку клавиатурой. Основное применение — модальные окна, всплывающие панели, аккордеоны, где важно, чтобы пользователь не мог случайно переместить фокус вне активной зоны.
Для реализации зоны сброса достаточно обернуть интерактивные элементы
в контейнер и использовать tabbable для отслеживания всех
табулируемых элементов:
import { tabbable } from 'tabbable';
const modal = document.querySelector('.modal');
const elements = tabbable(modal);
elements вернёт массив в порядке, в котором элементы
должны получать фокус при нажатии Tab.
Для предотвращения выхода фокуса за пределы зоны используют
обработчики событий keydown:
modal.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
const elements = tabbable(modal);
const first = elements[0];
const last = elements[elements.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
preventDefault() предотвращает стандартное поведение
браузера, обеспечивая замкнутую последовательность.В современных интерфейсах элементы могут динамически добавляться или удаляться. В таких случаях важно обновлять массив tabbable-элементов перед каждой проверкой фокуса:
function getTabbableElements(container) {
return tabbable(container);
}
Это гарантирует, что новые элементы будут корректно включены в последовательность, а удалённые — исключены.
Для доступности крайне важно учитывать атрибуты ARIA, которые могут скрывать или показывать элементы:
aria-hidden="true" исключает элемент из
tabbable-последовательности.display: none)
также автоматически игнорируются.tabindex="-1" и программного фокуса
позволяет управлять доступностью без изменения визуального порядка
элементов.При больших интерфейсах повторное вычисление tabbable-элементов может быть затратным. Рекомендуется:
tabbable(container) только при добавлении или
удалении интерактивных элементов.keydown.tabindex="0" для кастомных кнопок и
интерактивных блоков.Эффективное применение Tabbable обеспечивает предсказуемую и безопасную навигацию с клавиатуры, предотвращает потерю фокуса и повышает доступность веб-приложений.