ARIA-атрибуты

ARIA (Accessible Rich Internet Applications) — это набор атрибутов, предназначенных для повышения доступности веб-приложений. Dragula, как библиотека для реализации drag-and-drop интерфейсов, требует особого внимания к корректной работе с ARIA, чтобы элементы, которые перетаскиваются, были доступны для пользователей вспомогательных технологий, таких как экранные читалки.

Роль и состояние перетаскиваемого элемента

Каждый элемент, который может быть перемещён с помощью Dragula, должен иметь правильно заданную роль. Наиболее подходящей является роль listitem в составе контейнера с ролью list:

<div role="list" id="container">
    <div role="listitem" draggable="true">Элемент 1</div>
    <div role="listitem" draggable="true">Элемент 2</div>
</div>

Ключевые моменты:

  • draggable="true" позволяет браузеру распознавать элемент как интерактивный для drag-and-drop.
  • Роли list и listitem обеспечивают семантическую структуру, понятную вспомогательным технологиям.
  • При перемещении элемента необходимо обновлять атрибут aria-grabbed.

Атрибут aria-grabbed отражает текущее состояние элемента:

  • aria-grabbed="true" — элемент выбран для перетаскивания.
  • aria-grabbed="false" — элемент не выбран.

В Dragula это можно реализовать через прослушку событий drag и dragend:

dragula([document.getElementById('container')])
  .on('drag', function (el) {
      el.setAttribute('aria-grabbed', 'true');
  })
  .on('dragend', function (el) {
      el.setAttribute('aria-grabbed', 'false');
  });

Обновление ARIA-контейнера

Для поддержания корректного взаимодействия с экранными читалками важно обновлять атрибут aria-dropeffect у контейнеров. Этот атрибут указывает, какие действия допустимы при перетаскивании в данный контейнер:

var containers = [document.getElementById('container')];
containers.forEach(function(container) {
    container.setAttribute('aria-dropeffect', 'move');
});
  • move — элемент будет перемещён.
  • copy — элемент будет скопирован.
  • none — перетаскивание в этот контейнер запрещено.

При Dragula необходимо динамически изменять aria-dropeffect в зависимости от текущей операции. Например, при наведении перетаскиваемого элемента на контейнер:

dragula(containers)
  .on('over', function (el, container) {
      container.setAttribute('aria-dropeffect', 'move');
  })
  .on('out', function (el, container) {
      container.setAttribute('aria-dropeffect', 'none');
  });

Поддержка клавиатурного взаимодействия

ARIA-атрибуты позволяют организовать не только визуальное, но и клавиатурное взаимодействие с элементами Dragula. Для этого:

  • Элемент должен быть фокусируемым (tabindex="0").
  • Использовать события клавиатуры для имитации drag-and-drop.

Пример:

<div role="list" id="container">
    <div role="listitem" tabindex="0" aria-grabbed="false">Элемент 1</div>
</div>

С помощью обработчика keydown можно изменять aria-grabbed и aria-dropeffect для имитации перетаскивания:

document.querySelectorAll('[role="listitem"]').forEach(function(el) {
    el.addEventListener('keydown', function(e) {
        if (e.key === " " || e.key === "Enter") {
            var grabbed = el.getAttribute('aria-grabbed') === 'true';
            el.setAttribute('aria-grabbed', grabbed ? 'false' : 'true');
        }
    });
});

Актуализация положения элементов

После завершения перетаскивания важно обновлять ARIA-структуру, чтобы экранные читалки корректно озвучивали новую последовательность элементов:

dragula(containers).on('drop', function (el, target, source, sibling) {
    Array.from(target.children).forEach(function(child, index) {
        child.setAttribute('aria-posinset', index + 1);
        child.setAttribute('aria-setsize', target.children.length);
    });
});
  • aria-posinset — позиция элемента в списке.
  • aria-setsize — общее количество элементов в контейнере.

Совместимость с динамическими контейнерами

Dragula часто используется с контейнерами, которые создаются динамически. В этом случае:

  1. Необходимо присваивать ARIA-атрибуты сразу после генерации контейнера.
  2. Обновлять события Dragula для новых элементов.

Пример динамического добавления элемента:

var container = document.getElementById('container');
var newItem = document.createElement('div');
newItem.setAttribute('role', 'listitem');
newItem.setAttribute('draggable', 'true');
newItem.setAttribute('aria-grabbed', 'false');
newItem.textContent = 'Новый элемент';
container.appendChild(newItem);

// Обновление Dragula
dragula([container]);

Использование вспомогательных ARIA-атрибутов

Для более точного описания состояния drag-and-drop можно использовать:

  • aria-label — описание элемента для экранного читалки.
  • aria-describedby — ссылка на элемент с дополнительной информацией.
  • aria-live="polite" — динамическое уведомление о перемещении элементов.
var liveRegion = document.createElement('div');
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.style.position = 'absolute';
liveRegion.style.left = '-9999px';
document.body.appendChild(liveRegion);

dragula([container])
  .on('drop', function (el, target) {
      liveRegion.textContent = `${el.textContent} перемещён в новый контейнер`;
  });

Рекомендации по совместимости

  • Проверять ARIA-атрибуты на каждой стадии drag-and-drop.
  • Обновлять состояние элементов не только визуально, но и через aria-*.
  • Использовать сочетание aria-grabbed и aria-dropeffect для корректной работы со вспомогательными технологиями.
  • Поддерживать клавиатурное управление через фокус и обработку клавиш.

ARIA-атрибуты в Dragula обеспечивают полноценную доступность интерфейса, позволяя пользователям с ограниченными возможностями видеть и управлять элементами списка наравне с мышью. Корректная реализация этих атрибутов превращает простой drag-and-drop в полностью инклюзивное взаимодействие.