L'accessibilità web non è un "optional". È una responsabilità. Quando costruiamo interfacce complesse con JavaScript – modali, menu, dropdown, carousel, tooltip – stiamo spesso rompendo il comportamento nativo del browser. Se non ci preoccupiamo di ripristinare ciò che il browser faceva automaticamente (focus, navigazione da tastiera, semantica), rendiamo l'app inutilizzabile per molte persone.
In questo articolo vedremo:
- Perché l'accessibilità con JavaScript è cruciale.
- Cos'è davvero il focus management.
- Come e quando usare ARIA.
- Cosa significa progettare componenti "keyboard-first".
- Errori comuni da evitare.
- Alcuni sempi pratici.
Il problema: JavaScript rompe la semantica nativa
HTML è accessibile per default.
Un button:
- È focusabile.
- Risulta cliccabile da tastiera.
- Espone il ruolo corretto.
- Annuncia il suo nome agli screen reader.
Ma quando usiamo JavaScript per costruire componenti custom, spesso partiamo da div.
<div class="button">Clicca</div>
Visivamente sembra un bottone. Ma per una persona che usa la tastiera o uno screen reader non lo è. Non è focusabile. Non è attivabile con Enter o Space.Non ha un ruolo. Non ha un nome accessibile. Qui nasce il problema.
Accessibilità ≠ solo screen reader
Quando si parla di accessibilità, molti pensano solo agli screen reader. In realtà riguarda anche:
- Persone che usano solo la tastiera.
- Utenti con tremori o difficoltà motorie.
- Persone con deficit visivi parziali.
- Utenti con ADHD.
- Persone con difficoltà cognitive.
- Soggtti temporaneamente disabili (braccio rotto, luce forte, ecc.).
La tastiera è quindi il minimo sindacale.
Focus management in JavaScript: cos'è e perché è fondamentale
Il focus è l'indicatore di dove si trova l'utente nella pagina. Con il mouse è ovvio. Con la tastiera, è tutto. Se non sai dove sei, sei perso.
Ecco alcuni problemi comuni di focus.
- Apro una modale e il focus rimane dietro.
- Chiudo una modale e il focus sparisce.
- Apro un menu e tab naviga fuori.
- Un elemento appare e non viene annunciato.
Gestire il focus manualmente
Quando crei componenti dinamici, devi gestire tu il focus.
Spostare il focus:
element.focus();
Rendere un elemento focusabile:
<div>Elemento focusabile</div>
Attenzione: tabindex="0" va usato con parsimonia. Se stai creando un bottone, usa button
Focus trap in una modale con JavaScript
Quando una modale è aperta Il focus non deve uscire, Tab e Shift+Tab devono ciclare dentro:
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
Poi intercetti Tab e Shift+Tab per mantenerlo dentro.
Restituire il focus
Quando chiudi un componente, restituisci il focus da dove veniva.
let lastFocused;
button.addEventListener("click", () => {
lastFocused = document.activeElement;
modal.open();
});
closeButton.addEventListener("click", () => {
modal.close();
lastFocused.focus();
});
Semplice, ma spesso dimenticato.
ARIA: cos'è e cosa non è
ARIA (Accessible Rich Internet Applications) serve a descrivere ai lettori di schermo ciò che non è già descritto semanticamente. Non è una scusa per usare div ovunque.
Non usare ARIA se puoi usare HTML nativo. Se ti serve un bottone usa button non <div role="button">:
<div role="button"></div>
<div role="dialog"></div>
<div role="navigation"></div>
Ma ripeto: se esiste un tag semantico, usalo.
Stati ARIA
ARIA serve soprattutto per comunicare stati dinamici:
<button aria-expanded="false">Menu</button>
Quando il menu si apre:
button.setAttribute("aria-expanded", "true");
Per le label accessibili un esempio potrebbe essere:
<button aria-label="Chiudi finestra">X</button>
Oppure:
<div aria-labelledby="title-id"></div>
Live regions: annunciare cambiamenti
Se il contenuto cambia dinamicamente, lo screen reader non lo sa. Per questo esiste aria-live:
<div aria-live="polite" id="status"></div>
status.textContent = "Messaggio inviato";
Ora lo screen reader lo annuncia.
Keyboard-first: progettare partendo dalla tastiera con JavaScript
Un componente è veramente accessibile solo se funziona prima con la tastiera, poi con il mouse. Non il contrario. Quando progetti un componente, chiediti:
- Posso usarlo interamente con Tab?
- Lo posso attivare con Enter e Space?
- Si può uscire facilmente?
- Posso capire dove sono?
Ecco un esempio di dropdown accessibile. Versione sbagliata:
<div class="dropdown">Menu</div>
Non focusabile, non cliccabile, non navigabile. Versione corretta:
<button aria-expanded="false" aria-controls="menu">
Menu
</button>
<ul id="menu" hidden>
<li><a href="#">Profilo</a></li>
<li><a href="#">Impostazioni</a></li>
</ul>
Con JavaScript:
button.addEventListener("click", () => {
const expanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", String(!expanded));
menu.hidden = expanded;
});
Gestire le frecce
Molti componenti (menu, listbox, tablist) prevedono navigazione con frecce:
item.addEventListener("keydown", e => {
if (e.key === "ArrowDown") {
nextItem.focus();
}
});
Mai rimuovere l'outline:
:focus {
outline: none;
}
È uno degli errori peggiori e se lo rimuovi, sostituiscilo:
:focus {
outline: 3px solid blue;
}
div.addEventListener("click", ...)
Devi gestire anche invio e spazio. Non usare poi Tabindex ovunque, non è una bacchetta magica. Se poi non sai cosa fa un attributo ARIA, non usarlo.
Inoltre, mai usare solo la tastiera Stacca il mouse. Naviga. Riesci a usare tutto? Testa lo Screen reader di riferimento:
- VoiceOver (Mac).
- NVDA (Windows).
- JAWS.
Non serve essere esperti: basta capire se è usabile. L'accessibilità non è una feature, è parte del design. Un buon componente è comprensibile, usabile, prevedibile e robustamente navigabile.
Conclusione
L'accessibilità non è un dettaglio, non è un "nice to have" e non è qualcosa che si aggiunge alla fine del progetto se avanza tempo. È una caratteristica strutturale dell'interfaccia, tanto quanto le performance o la sicurezza.
Quando usiamo JavaScript per costruire componenti personalizzati, stiamo implicitamente riscrivendo regole che il browser ha già risolto per noi: gestione del focus, navigazione da tastiera, semantica, annunci agli screen reader. Se non ci prendiamo la responsabilità di ricostruire questi comportamenti, stiamo creando interfacce visivamente belle ma funzionalmente rotte per una parte degli utenti.
Progettare componenti "keyboard-first" non significa penalizzare chi usa il mouse. Significa creare interfacce più robuste, più prevedibili e più facili da usare per tutti. La tastiera ti costringe a pensare in termini di flusso, struttura e gerarchia.
ARIA, da parte sua, non è una bacchetta magica. È uno strumento potente, ma va usato con rispetto. Ogni attributo è una promessa fatta agli utenti che usano tecnologie assistive. Se la rompi ne pagano le conseguenze.
La buona notizia è che l'accessibilità non richiede superpoteri ma attenzione, empatia e un cambio di prospettiva. Basta iniziare da una domanda semplice: posso usare questa interfaccia senza vedere, senza mouse, senza precisione? Se la risposta è sì, allora stai andando nella direzione giusta.