Les interfaces de glisser-déposer sont devenues un standard des applications web modernes, offrant une méthode intuitive pour réorganiser des listes, déplacer des fichiers ou gérer des flux de travail. Cependant, un écueil courant dans le développement frontend est de privilégier les interactions souris au détriment de l'accessibilité clavier. Pour les utilisateurs qui dépendent de lecteurs d'écran ou d'une navigation au clavier uniquement, une implémentation standard du glisser-déposer constitue souvent une barrière à l'entrée. Cet article explore comment mettre en œuvre une fonctionnalité de glisser-déposer robuste et accessible en utilisant uniquement JavaScript natif et les normes WAI-ARIA, garantissant ainsi que votre application soit utilisable par tout le monde.
Pourquoi l'accessibilité clavier est essentielle dans le glisser-déposer
Le glisser-déposer traditionnel repose fortement sur l'API des événements souris (mousedown, mousemove, mouseup). Bien que cela fonctionne bien pour les utilisateurs de souris, cela exclut complètement les utilisateurs du clavier. Selon les directives WCAG 2.1, toute fonctionnalité disponible via une interface souris doit également être disponible via le clavier. Cela signifie que nous avons besoin d'une approche double : prendre en charge le glissement natif lorsque cela est possible, mais surtout, fournir un « mode clavier » alternatif qui permet aux utilisateurs de déplacer des éléments à l'aide des flèches et des touches Entrée/Espace.
Les rôles et états WAI-ARIA fondamentaux
Pour communiquer l'état de nos éléments interactifs aux technologies d'assistance, nous devons utiliser des rôles WAI-ARIA spécifiques. Le modèle le plus courant consiste à utiliser role="listbox" pour le conteneur et role="option" pour les éléments glissables. Nous devons également gérer l'état dynamiquement à l'aide d'attributs tels que :
aria-grabbed: Indique si un élément est glissable (true) ou non (false).aria-dropeffect: Indique l'action qui se produit lorsque l'élément est déposé (par ex. « move », « copy »).aria-activedescendant: Pointe vers l'option actuellement focus ou « active » dans la listbox, aidant les lecteurs d'écran à suivre la position.
Mise en œuvre de la logique de glisser-déposer accessible
Voici une implémentation simplifiée d'un mécanisme de réorganisation de liste. Cet exemple se concentre sur la logique d'interaction clavier, qui est souvent l'aspect le plus négligé de l'accessibilité.
const listContainer = document.getElementById('item-list');
const items = Array.from(listContainer.querySelectorAll('[role="option"]'));
// Helper de gestion du focus
let currentIndex = 0;
function moveItem(direction) {
const current = items[currentIndex];
// Déterminer l'index cible en fonction de la direction ('up' ou 'down')
const newIndex = direction === 'up'
? currentIndex - 1
: currentIndex + 1;
// Vérifications des limites
if (newIndex < 0 || newIndex >= items.length) return;
const target = items[newIndex];
// Échanger les éléments dans le DOM
if (direction === 'up') {
listContainer.insertBefore(current, target);
} else {
listContainer.insertBefore(target, current);
}
// Mettre à jour l'ordre du tableau pour refléter les changements du DOM
const tempItems = Array.from(listContainer.querySelectorAll('[role="option"]'));
const oldIndex = items.indexOf(current);
items.splice(oldIndex, 1);
items.splice(newIndex, 0, current);
// Déplacer le focus vers l'élément nouvellement positionné
target.focus();
listContainer.setAttribute('aria-activedescendant', target.id);
// Annoncer le changement au lecteur d'écran
current.setAttribute('aria-label', `Moved ${direction}`);
}
// Écouteur d'événements pour la navigation clavier
listContainer.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp') {
e.preventDefault();
moveItem('up');
} else if (e.key === 'ArrowDown') {
e.preventDefault();
moveItem('down');
}
});
Améliorer l'expérience souris
Bien que le code ci-dessus gère la navigation clavier, une solution complète doit également prendre en charge le glissement à la souris. Pour cela, vous pouvez utiliser l'API HTML5 Drag and Drop ou une bibliothèque comme SortableJS (configurée pour l'accessibilité). L'essentiel est de s'assurer que lorsqu'un élément est saisi à la souris, son état aria-grabbed est mis à jour sur true, et qu'il revient à false lors du relâchement.
// Exemple de mise à jour de l'état ARIA pendant le glissement souris
function onDragStart(event) {
event.target.setAttribute('aria-grabbed', 'true');
event.dataTransfer.effectAllowed = 'move';
}
function onDragEnd(event) {
event.target.setAttribute('aria-grabbed', 'false');
}
Tests et validation
Après l'implémentation, des tests rigoureux sont essentiels. Utilisez des outils tels que Web Accessibility Evaluation Tools (WAVE) pour vérifier la validité des attributs ARIA. Plus important encore, testez votre interface avec un lecteur d'écran (tel que NVDA ou VoiceOver) et naviguez uniquement au clavier. Assurez-vous que l'utilisateur reçoit un retour auditif clair lorsque les éléments bougent et que l'ordre du focus reste logique.
Conclusion
Implémenter des interfaces de glisser-déposer accessibles ne concerne pas seulement la conformité ; c'est une question d'empathie et d'inclusion. En combinant les attributs WAI-ARIA avec la logique JavaScript native, nous pouvons créer des expériences riches et interactives qui fonctionnent de manière transparente pour tous les utilisateurs, quelle que soit leur méthode de saisie. En tant que développeurs frontend, notre responsabilité va au-delà de l'esthétique visuelle pour garantir que nos applications sont ouvertes et utilisables par tout le monde.