Gridstack.js предоставляет мощные инструменты для управления сетками и виджетами в веб-приложениях, включая обработку фокуса элементов и навигацию с помощью клавиши Tab. Понимание этих механизмов критично для создания доступного и интерактивного интерфейса.
В Gridstack.js каждый виджет
(grid-item) может быть сфокусирован с помощью
стандартных методов DOM:
const widget = document.querySelector('.grid-stack-item');
widget.focus();
Для того чтобы виджет корректно получал фокус, он должен иметь
атрибут tabindex:
<div class="grid-stack-item" tabindex="0">
<div class="grid-stack-item-content">Контент</div>
</div>
Ключевые моменты:
tabindex="0" позволяет элементу участвовать в
естественной последовательности табуляции.tabindex="-1" делает элемент доступным для программной
фокусировки, но исключает из стандартного порядка Tab.Gridstack.js не блокирует стандартную клавиатурную навигацию, однако при сложной сетке могут возникать нестандартные переходы между виджетами. Для правильной табуляции рекомендуется:
tabindex.focus и blur для
реализации визуальных индикаторов фокуса.Пример обработки событий:
const grid = GridStack.init();
grid.on('added', (event, items) => {
items.forEach(item => {
const el = item.el;
el.setAttribute('tabindex', '0');
el.addEventListener('focus', () => {
el.classList.add('focused');
});
el.addEventListener('blur', () => {
el.classList.remove('focused');
});
});
});
Gridstack.js позволяет перетаскивать и изменять размеры виджетов с помощью drag-and-drop. Важно, чтобы фокус не терялся при интерактивных действиях:
dragstart для сохранения текущего
элемента с фокусом.dragstop возвращать фокус на тот же
виджет:grid.on('dragstart', (event, el) => {
el.dataset.prevFocus = document.activeElement === el ? 'true' : 'false';
});
grid.on('dragstop', (event, el) => {
if (el.dataset.prevFocus === 'true') {
el.focus();
delete el.dataset.prevFocus;
}
});
Аналогично, при изменении размера через событие
resizestop можно обеспечить сохранение фокуса:
grid.on('resizestop', (event, el) => {
el.focus();
});
Для управления навигацией с помощью клавиши Tab можно реализовать собственный порядок перемещения между виджетами:
const widgets = Array.from(document.querySelectorAll('.grid-stack-item'));
widgets.forEach((widget, index) => {
widget.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
let nextIndex = e.shiftKey ? index - 1 : index + 1;
if (nextIndex >= widgets.length) nextIndex = 0;
if (nextIndex < 0) nextIndex = widgets.length - 1;
widgets[nextIndex].focus();
}
});
});
Особенности:
e.shiftKey позволяет обрабатывать обратную навигацию
(Shift+Tab).Если виджет содержит интерактивные элементы формы, важно корректно обрабатывать фокус внутри виджета и между виджетами:
const inputs = widget.querySelectorAll('input, select, textarea, button');
inputs.forEach(input => {
input.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.stopPropagation(); // предотвращаем срабатывание глобальной табуляции
}
});
});
Такой подход позволяет:
Gridstack.js не предоставляет встроенных средств управления доступностью, поэтому важно:
aria-* атрибуты для виджетов
(role="region", aria-label).outline,
box-shadow).tabindex
и события keydown.Пример доступного виджета:
<div class="grid-stack-item" tabindex="0" role="region" aria-label="Виджет статистики">
<div class="grid-stack-item-content">Статистика</div>
</div>
tabindex.keydown.aria-* для поддержки
доступности.Эти практики позволяют создавать интерактивные, доступные и удобные сетки в Gridstack.js, где навигация клавиатурой становится естественной и предсказуемой.