Библиотека Tabbable в JavaScript предназначена для работы с элементами интерфейса, которые могут получать фокус при навигации с помощью клавиши Tab. Основное назначение — выявление всех «доступных для табуляции» элементов на странице или внутри контейнера, что особенно важно для реализации доступности (accessibility) и управления фокусом в сложных интерфейсах.
Элемент считается tabbable, если он удовлетворяет следующим условиям:
tabindex >= 0 или является стандартным
интерактивным элементом (например, <button>,
<input>, <a href="">).display: none,
visibility: hidden) и не находится внутри скрытого
контейнера.disabled для <button>
или <input>).Библиотека позволяет получить список всех таких элементов, а также управлять их состоянием программно.
Для получения элементов используется функция:
import { tabbable } from 'tabbable';
const container = document.querySelector('#form');
const focusableElements = tabbable(container);
tabbable(container) возвращает массив
DOM-элементов, которые могут быть достигнуты с помощью
клавиши Tab. Если контейнер не указан, функция ищет tabbable элементы в
документе целиком.
Ключевые моменты:
После получения tabbable элементов часто требуется программно
переместить фокус. Для этого используется метод
focus():
focusableElements[0].focus(); // фокус на первом элементе
Можно реализовать циклическую навигацию по элементам:
let index = 0;
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
index = (index + 1) % focusableElements.length;
focusableElements[index].focus();
}
});
Эта схема особенно полезна для модальных окон, где необходимо ограничить фокус только внутри модального контейнера.
При динамических интерфейсах важно не только определить tabbable элементы, но и сохранять текущий фокус, чтобы при обновлении содержимого возвращать пользователя к тому же элементу.
Пример сохранения фокуса:
let lastFocusedElement = document.activeElement;
const updateUI = () => {
const container = document.querySelector('#form');
// обновление DOM
container.innerHTML = renderForm();
// восстановление фокуса
if (lastFocusedElement && container.contains(lastFocusedElement)) {
lastFocusedElement.focus();
} else {
const firstFocusable = tabbable(container)[0];
if (firstFocusable) firstFocusable.focus();
}
};
document.addEventListener('focusin', (e) => {
lastFocusedElement = e.target;
});
Особенности подхода:
focusin для отслеживания текущего
активного элемента.Иногда интерфейс содержит элементы, которые не поддерживают фокус по
умолчанию (<div> с обработкой событий). Для их
включения в навигацию необходимо использовать tabindex:
<div tabindex="0">Кликабельный блок</div>
<div tabindex="1">Еще один блок</div>
tabindex="0" добавляет элемент в естественный порядок
табуляции.tabindex > 0 изменяет порядок вручную, что позволяет
управлять приоритетами фокуса.tabindex="-1" делает элемент фокусируемым только
программно (element.focus()), исключая из стандартной
навигации Tab.Библиотека позволяет фильтровать элементы по кастомным условиям. Например, исключение элементов с определённым классом:
const container = document.querySelector('#form');
const focusableElements = tabbable(container).filter(el => !el.classList.contains('skip'));
Можно реализовать динамические условия, например игнорировать поля, недоступные по логике приложения, даже если они видимы и фокусируемы.
Tabbable особенно полезен в крупных интерфейсах:
Программная навигация позволяет поддерживать полную доступность без вмешательства в нативное поведение браузера.
document.activeElement для
восстановления фокуса после изменений DOM.tabindex для управления нестандартными
элементами.Tab и Shift+Tab.Эта стратегия обеспечивает стабильное поведение фокуса, совместимость с экранными считывателями и удобную клавиатурную навигацию в сложных интерфейсах.