Библиотека Tabbable в JavaScript предназначена для определения элементов на веб-странице, которые могут получать фокус с помощью клавиши Tab. Она облегчает управление навигацией по интерфейсу, особенно в сложных компонентах с модальными окнами, панелями или кастомными элементами управления.
Основной принцип: Tabbable определяет, какие элементы являются интерактивными и могут быть сфокусированы. К ним относятся:
<input>, <textarea>,
<select>, <button>tabindex="0"contenteditable="true"<a> с атрибутом hrefЭлементы с tabindex="-1" исключаются из
последовательности табуляции, но могут получать фокус программно.
1. tabbable(container) Возвращает
массив всех tabbable-элементов внутри контейнера.
Пример использования:
import { tabbable } from 'tabbable';
const container = document.querySelector('#modal');
const focusableElements = tabbable(container);
console.log(focusableElements); // Массив элементов, доступных для Tab
Особенность: порядок элементов соответствует их визуальной последовательности на странице, что особенно важно для доступности.
2. isTabbable(element) Возвращает
true, если элемент может быть сфокусирован через Tab, и
false, если нет.
import { isTabbable } from 'tabbable';
const button = document.querySelector('button');
console.log(isTabbable(button)); // true или false
Этот метод полезен для динамической проверки доступности элементов, например, при изменении состояния UI.
3. focusable(container) Возвращает все
элементы, которые могут получить фокус программно, включая элементы с
tabindex="-1". Отличается от tabbable, который
учитывает только Tab-последовательность.
import { focusable } from 'tabbable';
const allFocusable = focusable(document.body);
tabindextabindex управляет доступностью элемента:
Tabbable автоматически учитывает эти значения при формировании массива фокусируемых элементов.
Для модальных окон важно ограничить фокус внутри контейнера. Tabbable помогает реализовать focus trap:
const modal = document.querySelector('#modal');
const elements = tabbable(modal);
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
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();
}
}
});
Такой подход обеспечивает циклическую навигацию по элементам модального окна, исключая уход фокуса за пределы модалки.
Хотя Tabbable не отвечает за визуальное выделение, она тесно связана с реализацией индикаторов фокуса:
outline) при получении
фокусаЭти эффекты применяются через CSS, а Tabbable предоставляет массив элементов для точного определения, на каком элементе фокус находится.
Пример подсветки активного элемента:
const items = tabbable(document.querySelector('#pagination'));
items.forEach(item => {
item.addEventListener('focus', () => item.classList.add('active'));
item.addEventListener('blur', () => item.classList.remove('active'));
});
Для элементов пагинации Tabbable позволяет:
Пример управления пагинацией через клавиши стрелок:
const pages = tabbable(document.querySelector('#pagination'));
document.addEventListener('keydown', (e) => {
const currentIndex = pages.indexOf(document.activeElement);
if (e.key === 'ArrowRight') {
e.preventDefault();
const next = pages[(currentIndex + 1) % pages.length];
next.focus();
} else if (e.key === 'ArrowLeft') {
e.preventDefault();
const prev = pages[(currentIndex - 1 + pages.length) % pages.length];
prev.focus();
}
});
Tabbable позволяет корректно работать с элементами, которые добавляются или удаляются динамически:
tabbable(container) для обновления массива фокусируемых
элементов.const observer = new MutationObserver(() => {
const elements = tabbable(document.querySelector('#dynamic'));
console.log(elements);
});
observer.observe(document.querySelector('#dynamic'), { childList: true, subtree: true });
tabindex, а учитывать реальные
возможности элемента быть tabbable.Правильное использование Tabbable делает интерфейсы доступными, предсказуемыми и удобными для пользователей с клавиатурной навигацией, особенно при работе с модальными окнами и компонентами с пагинацией.