Une interface accessible commence par du HTML natif. Les boutons restent des boutons, les champs ont un label et chaque tâche possède un nom compréhensible hors contexte.
Le HTML
~~~html <main> <h1>Mes tâches</h1> <form id="task-form"> <label for="task-title">Nouvelle tâche</label> <input id="task-title" required maxlength="120" /> <button type="submit">Ajouter</button> </form> <p id="status" aria-live="polite"></p> <ul id="task-list"></ul> </main> ~~~
Le formulaire fonctionne avec Entrée sans gestionnaire clavier personnalisé. aria-live annonce uniquement les changements importants.
Ajouter une tâche
~~~javascript const form = document.querySelector('#task-form'); const input = document.querySelector('#task-title'); const list = document.querySelector('#task-list'); const status = document.querySelector('#status'); let tasks = JSON.parse(localStorage.getItem('tasks') ?? '[]');
function save() { localStorage.setItem('tasks', JSON.stringify(tasks)); }
function render() { list.replaceChildren(...tasks.map(task => { const li = document.createElement('li'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = task.done; checkbox.id = 'task-' + task.id; checkbox.addEventListener('change', () => { task.done = checkbox.checked; save(); render(); }); const label = document.createElement('label'); label.htmlFor = checkbox.id; label.textContent = task.title; const remove = document.createElement('button'); remove.type = 'button'; remove.textContent = 'Supprimer ' + task.title; remove.addEventListener('click', () => removeTask(task.id)); li.append(checkbox, label, remove); return li; })); }
form.addEventListener('submit', event => { event.preventDefault(); const title = input.value.trim(); if (!title) return; tasks.push({ id: crypto.randomUUID(), title, done: false }); save(); render(); input.value = ''; input.focus(); status.textContent = 'Tâche ' + title + ' ajoutée'; }); ~~~
Dans removeTask, mémorisez l’élément voisin avant suppression, puis placez le focus dessus ou sur le champ d’ajout. Annoncez la suppression sans déplacer brutalement le lecteur d’écran.
Vérifier
Parcourez toute l’application avec Tab, Maj+Tab, Entrée et Espace. Testez zoom 200 %, contraste, erreurs du formulaire et un lecteur d’écran. Aucun contrôle ne doit dépendre uniquement de la couleur ou du pointeur.
FAQ
Faut-il ajouter role=button ?
Non sur un élément button : sa sémantique est déjà correcte.
localStorage convient-il à des données sensibles ?
Non. Il est accessible au JavaScript de la page et ne remplace pas un stockage serveur sécurisé.