Библиотека Tabbable предназначена для определения всех элементов на веб-странице, которые могут быть сфокусированы с помощью клавиши Tab. Она не изменяет поведение браузера, а лишь предоставляет удобный способ работы с фокусируемыми элементами. В контексте переключения между панелями это особенно важно, так как позволяет программно управлять навигацией без вмешательства в стандартное поведение клавиатуры.
tabbable(container): возвращает массив всех
фокусируемых элементов внутри указанного контейнера.isTabbable(element): проверяет, можно ли элемент
фокусировать через Tab.focusable(element): возвращает true, если элемент может
получить фокус программно (не обязательно через Tab).Пример базового использования:
import { tabbable } from 'tabbable';
const panel = document.querySelector('#panel-1');
const focusableElements = tabbable(panel);
console.log(focusableElements);
Этот код вернёт массив всех элементов, на которые пользователь может
переключиться с помощью клавиши Tab внутри панели
#panel-1.
В интерфейсах с несколькими панелями важно управлять порядком фокусируемых элементов. Например, при закрытии одной панели фокус нужно переносить на следующую или предыдущую панель, чтобы пользователь не терял ориентир.
Для каждой панели можно создать отдельный список элементов:
const panels = document.querySelectorAll('.panel');
const panelTabbables = Array.from(panels).map(panel => ({
panel,
elements: tabbable(panel)
}));
Теперь у каждой панели есть собственный массив элементов, пригодных для фокусировки. Это позволит реализовать:
Чтобы установить фокус на первый элемент панели:
function focusFirst(panel) {
const elements = tabbable(panel);
if (elements.length > 0) {
elements[0].focus();
}
}
Для фокусировки последнего элемента:
function focusLast(panel) {
const elements = tabbable(panel);
if (elements.length > 0) {
elements[elements.length - 1].focus();
}
}
Эти функции позволяют реализовать логику перехода между панелями при нажатии клавиш Tab и Shift+Tab.
Для полноценного переключения между панелями требуется слушать события клавиатуры и корректно определять направление навигации:
document.addEventListener('keydown', (event) => {
if (event.key !== 'Tab') return;
const activeElement = document.activeElement;
const currentPanelIndex = Array.from(panels).findIndex(panel =>
panel.contains(activeElement)
);
const currentPanelElements = panelTabbables[currentPanelIndex].elements;
if (!event.shiftKey && activeElement === currentPanelElements[currentPanelElements.length - 1]) {
event.preventDefault();
const nextIndex = (currentPanelIndex + 1) % panels.length;
focusFirst(panels[nextIndex]);
}
if (event.shiftKey && activeElement === currentPanelElements[0]) {
event.preventDefault();
const prevIndex = (currentPanelIndex - 1 + panels.length) % panels.length;
focusLast(panels[prevIndex]);
}
});
Ключевые моменты:
event.preventDefault() для предотвращения
стандартного поведения браузера.shiftKey реализуется обратное переключение.Если панели создаются или удаляются динамически, необходимо обновлять массив фокусируемых элементов:
function updatePanels() {
const panels = document.querySelectorAll('.panel');
panelTabbables.length = 0;
panels.forEach(panel => {
panelTabbables.push({
panel,
elements: tabbable(panel)
});
});
}
Это важно для интерфейсов с вкладками, модальными окнами и панелями с подгружаемым контентом.
Tabbable позволяет фильтровать элементы, которые не должны участвовать в цикле фокуса. Например, можно исключить скрытые элементы или те, которые временно недоступны:
import { tabbable } from 'tabbable';
const focusableVisible = tabbable(panel, { includeContainer: false }).filter(el => el.offsetParent !== null);
includeContainer: false исключает контейнер панели из
списка, что удобно, если фокус должен всегда оставаться внутри
внутренних элементов.
В современных фреймворках (React, Vue, Svelte) Tabbable особенно полезна для:
Преимущество в том, что библиотека не привязывается к конкретному фреймворку и работает напрямую с DOM, что делает её гибкой для интеграции в сложные интерфейсы.
display: none и
disabled, чтобы исключить нежелательные объекты из
цикла.Эти методы позволяют создавать интерфейсы с чётким и предсказуемым поведением клавиатурной навигации между панелями, полностью контролируя порядок фокуса и улучшая доступность.