Библиотека ally.js предоставляет мощные инструменты для управления фокусом и доступностью интерфейса, особенно в сценариях, где элементы динамически появляются или изменяют состояние, как это происходит при перетаскивании (drag-and-drop). Правильная работа с фокусом важна для поддержки клавиатурной навигации и экранных читалок.
Перетаскиваемые элементы часто изменяют порядок в DOM, что может нарушать последовательность фокуса. ally.js помогает контролировать фокус через:
Пример получения всех фокусируемых элементов внутри контейнера:
import * as ally from 'ally.js';
const container = document.querySelector('.drag-container');
const focusableElements = ally.query.focusable({ context: container });
focusableElements.forEach(el => {
console.log('Фокусируемый элемент:', el);
});
Такой подход позволяет программно управлять фокусом, предотвращая его потерю при перемещении элементов.
При drag-and-drop важно сохранять текущий фокус на перетаскиваемом элементе. Для этого ally.js предоставляет element.focus() и методы проверки видимости и интерактивности:
const draggedElement = document.querySelector('.dragging');
if (ally.is.focusable(draggedElement)) {
draggedElement.focus();
}
Использование ally.is.focusable гарантирует, что фокус
будет установлен только на элемент, способный принимать его,
предотвращая ошибки и неожиданные пропуски клавиш.
Перетаскивание часто сопровождается динамическими изменениями DOM. Чтобы сохранить доступность:
const newElement = document.createElement('div');
newElement.setAttribute('tabindex', '-1');
container.appendChild(newElement);
ally.focus(newElement);
const removedElement = document.querySelector('.dragged-out');
const previous = ally.next.focusable({ context: container, includeContext: true });
removedElement.remove();
if (previous) previous.focus();
Это предотвращает потерю фокуса и обеспечивает предсказуемое поведение клавиатурной навигации.
Для сложных интерфейсов, где перемещаемый элемент может быть внутри модального окна или сложной структуры, важно трапить фокус:
const trap = ally.maintain.focus({
context: container,
trap: true
});
// При завершении перетаскивания
trap.disengage();
Такой подход блокирует возможность случайного выхода фокуса из зоны перетаскивания, что критично для доступности.
Для полной синхронизации с действиями пользователя можно использовать стандартные события dragstart, dragend, dragover, комбинируя их с ally.js:
container.addEventListener('dragstart', event => {
const target = event.target;
if (ally.is.focusable(target)) {
target.setAttribute('aria-grabbed', 'true');
target.focus();
}
});
container.addEventListener('dragend', event => {
const target = event.target;
target.removeAttribute('aria-grabbed');
ally.next.focusable({ context: container }).focus();
});
aria-grabbed помогает экранным читалкам понимать
состояние элемента, а ally.js гарантирует, что фокус корректно
перемещается после завершения перетаскивания.
ally.is.focusable).tabindex="-1"
для новых элементов перед фокусом.maintain.focus для предотвращения случайного ухода
фокуса.aria атрибутов с текущим
фокусом и операцией drag-and-drop.Использование ally.js в drag-and-drop интерфейсах делает их более предсказуемыми и доступными, обеспечивая корректное управление фокусом независимо от динамических изменений DOM.