Criteri di successo WCAG · Level A

WCAG 2.1.2: Nessuna trappola da tastiera

WCAG 2.1.2 richiede che gli utenti della tastiera non rimangano mai intrappolati all’interno di un componente: se il focus può essere spostato in un elemento dell’interfaccia utente usando la tastiera, deve essere anche possibile spostare il focus altrove usando solo la tastiera. Questo criterio è essenziale per gli utenti che si affidano esclusivamente alla navigazione tramite tastiera, incluse le persone con disabilità motorie e gli utenti di screen reader.

Cosa Significa Questa Regola

WCAG 2.1.2 — Nessuna trappola da tastiera — è un criterio di successo di Livello A sotto il principio Operabile. Stabilisce: «Se il focus da tastiera può essere spostato su un componente della pagina usando un’interfaccia da tastiera, allora il focus può essere spostato via da quel componente usando solo un’interfaccia da tastiera e, se per spostare il focus via è necessario qualcosa di più dei tasti freccia non modificati o del tasto Tab, l’utente è informato del metodo per spostare il focus.»

In termini pratici, questo significa che ogni componente interattivo su una pagina web in cui un utente da tastiera può entrare con il tasto Tab deve anche permettere all’utente di uscirne con il Tab. Si verifica una trappola da tastiera quando un utente entra in un widget, una finestra di dialogo, un controllo di form personalizzato, un lettore multimediale incorporato o qualsiasi altra area focalizzabile e poi non riesce a uscirne usando i comandi standard da tastiera — in pratica, rimane bloccato.

Il criterio copre tutti gli elementi HTML che possono ricevere il focus da tastiera: elementi interattivi nativi come i tag <input>, <select>, <textarea>, <button> e <a>, così come i widget personalizzati che ricevono il focus tramite tabindex, ruoli ARIA o gestione del focus via JavaScript. Si applica allo stesso modo a componenti di terze parti incorporati come widget di chat, lettori video, mappe incorporate, selettori di data ed editor di testo avanzato.

Un componente rispetta questo criterio se un utente da tastiera può sempre spostare il focus via da esso usando tasti standard — tipicamente Tab, Shift+Tab, Escape o i tasti freccia — oppure se la pagina informa chiaramente gli utenti di un meccanismo da tastiera non standard per spostare il focus via. Un componente non rispetta il criterio se il focus rimane bloccato al suo interno senza alcun percorso di uscita accessibile da tastiera, o se l’unico meccanismo di uscita richiede un clic del mouse, un gesto touch o un altro input non da tastiera.

WCAG prevede una stretta eccezione: è accettabile limitare temporaneamente il focus da tastiera all’interno di un componente quando ciò fa parte di un pattern di design deliberato e accessibile — in particolare, una finestra di dialogo modale. Una finestra di dialogo modale dovrebbe intrappolare il focus all’interno della finestra mentre è aperta (per impedire agli utenti di interagire con il contenuto di sfondo oscurato), ma deve sempre fornire un modo accessibile da tastiera per chiudere la finestra e rilasciare il focus — ad esempio un gestore del tasto Escape o un pulsante di chiusura chiaramente etichettato e raggiungibile con Tab. Questo tipo di contenimento intenzionale e “evitabile” del focus non è una trappola da tastiera; è una corretta implementazione del pattern della finestra di dialogo modale. La trappola diventa una violazione solo quando l’utente non può affatto uscire.

Perché È Importante

Le trappole da tastiera sono tra i problemi di accessibilità più gravi che un sito web possa avere. A differenza di molti altri problemi di accessibilità che peggiorano l’esperienza per alcuni utenti, una trappola da tastiera può bloccare completamente un utente dal continuare a usare una pagina. È sostanzialmente l’equivalente di collocare una barriera fisica in un corridoio senza fornire alcuna via per aggirarla.

I gruppi più gravemente colpiti sono gli utenti con disabilità motorie o fisiche che non possono usare il mouse e si affidano interamente alla navigazione da tastiera. Questo include persone con condizioni come lesioni da sforzo ripetitivo, sclerosi multipla, morbo di Parkinson, tetraplegia e paralisi cerebrale. Secondo l’Organizzazione Mondiale della Sanità, circa 1,3 miliardi di persone — il 16% della popolazione globale — vivono con una qualche forma di disabilità significativa, e le disabilità motorie rappresentano una parte sostanziale di questa cifra. Per questi utenti, imbattersi in una trappola da tastiera su una pagina di checkout, un modulo di login o un widget di chat del servizio clienti può significare essere completamente impossibilitati a completare l’attività.

Anche gli utenti di screen reader — principalmente utenti ciechi e ipovedenti — sono fortemente colpiti. Gli screen reader come NVDA, JAWS e VoiceOver navigano interamente tramite comandi da tastiera. Se il focus rimane intrappolato in un componente, l’utente dello screen reader sente ripetere lo stesso elemento ogni volta che preme Tab, senza alcun modo per procedere avanti o indietro nella pagina. Questo è profondamente disorientante e costringe l’utente a chiudere la scheda del browser o aggiornare la pagina, perdendo qualsiasi progresso fatto.

Consideriamo questo scenario reale: un utente con mobilità limitata delle mani visita un sito di e-commerce turco per acquistare un prodotto. Aggiunge un articolo al carrello e procede al checkout. La pagina di checkout include un widget di autocompletamento dell’indirizzo di terze parti costruito con un framework JavaScript personalizzato. Il widget apre un elenco a discesa di suggerimenti quando il campo dell’indirizzo riceve il focus. Lo sviluppatore ha dimenticato di aggiungere la gestione degli eventi da tastiera per chiudere questo elenco a discesa — quindi, una volta che l’utente entra nel campo dell’indirizzo con Tab e appare il menu a discesa, non può uscire con Tab, non può premere Escape e non può chiudere il menu a discesa senza un clic del mouse. L’utente è completamente bloccato e non può completare l’acquisto. Questo non è un piccolo inconveniente — è una totale esclusione dal servizio.

Oltre all’accesso per le persone con disabilità, le trappole da tastiera colpiscono anche gli utenti esperti che preferiscono la navigazione da tastiera per velocità, gli utenti in ambienti aziendali in cui l’uso del mouse è limitato e gli utenti su alcuni dispositivi mobili o ibridi con tastiere hardware. Correggere le trappole da tastiera migliora quindi l’esperienza per un pubblico più ampio rispetto ai soli utenti con disabilità.

Regole Axe-core Correlate

WCAG 2.1.2 richiede test manuali. Nessuna regola automatizzata di axe-core rileva direttamente e in modo affidabile le trappole da tastiera. Questo perché gli strumenti automatizzati operano analizzando la struttura statica del DOM — possono identificare gli elementi focalizzabili, controllare l’ordine di tabulazione e convalidare gli attributi ARIA, ma non possono simulare l’intera esperienza di navigazione da tastiera interattiva che esegue un tester umano. Una trappola da tastiera emerge tipicamente dalla logica di gestione degli eventi JavaScript che intercetta o sopprime gli eventi da tastiera in fase di esecuzione; questo comportamento non è visibile nella struttura del DOM e non può essere dedotto da un analizzatore statico.

  • Test manuale richiesto — nessuna regola axe-core dedicata: Axe-core non include una regola che rilevi automaticamente le trappole da tastiera perché la modalità di errore è fondamentalmente comportamentale. La trappola si manifesta solo quando un utente entra effettivamente in un componente con il tasto Tab e tenta di uscirne. Uno scanner automatizzato non può replicare questo comportamento perché dovrebbe simulare la navigazione sequenziale da tastiera su ogni elemento focalizzabile della pagina, attivare tutti i listener di eventi JavaScript associati e poi determinare se il focus è uscito dall’area prevista — un problema computazionalmente intrattabile per pagine complesse. Inoltre, ciò che costituisce una trappola rispetto a un contenimento intenzionale del focus (come in un modale) richiede un giudizio contestuale che le regole automatizzate non possono fornire in modo affidabile. I tester dovrebbero usare axe DevTools o Lighthouse per identificare gli elementi focalizzabili e i problemi di ordine di tabulazione come punto di partenza, ma devono poi navigare manualmente con la tastiera in ogni area interattiva per confermare che non esistano trappole.

Come Eseguire i Test

  1. Esegui una scansione automatizzata di accessibilità come base. Apri axe DevTools (estensione del browser) o esegui un audit di accessibilità con Lighthouse in Chrome DevTools. Sebbene nessuno dei due strumenti segnali direttamente una trappola da tastiera, la scansione identificherà gli elementi focalizzabili, i ruoli ARIA mancanti e un ordine di tabulazione errato che può indicare componenti interattivi rischiosi da esaminare manualmente. Prendi nota di eventuali widget personalizzati, iframe incorporati, componenti di terze parti, finestre di dialogo modali, menu a discesa, selettori di data, caroselli ed editor di testo avanzato — queste sono le fonti più comuni di trappole da tastiera.
  2. Disconnetti o metti da parte il mouse. Perché il test manuale da tastiera sia valido, non devi usare il mouse. Metti il mouse fuori portata o disabilitalo nelle impostazioni del sistema operativo per evitare di fare affidamento su di esso accidentalmente durante i test.
  3. Navighi l’intera pagina usando solo i tasti Tab e Shift+Tab. A partire dalla barra degli indirizzi del browser o dalla parte superiore della pagina, premi ripetutamente Tab e osserva dove si sposta il focus. Segui visivamente l’indicatore di focus a ogni passaggio. Quando raggiungi ciascun componente interattivo — in particolare qualsiasi widget personalizzato, contenuto incorporato o elemento di interfaccia complesso — verifica che premendo Tab o Shift+Tab il focus esca correttamente dal componente e passi all’elemento focalizzabile successivo o precedente nella pagina.
  4. Testa ogni componente interattivo singolarmente. Per le finestre di dialogo modali: apri il modale, verifica che il focus si sposti al suo interno, poi premi Escape e conferma che il focus ritorna all’elemento che ha attivato il modale. Per i menu a discesa: apri il menu, naviga al suo interno, poi premi Escape e conferma che il menu si chiude e il focus ritorna al trigger. Per i selettori di data, selettori di colore e widget simili: entra con Tab, interagisci, poi esci con Tab e conferma che il focus esce. Per gli iframe incorporati (ad es. mappe, lettori video, widget di chat): entra nell’iframe con Tab, naviga al suo interno e conferma che puoi uscirne con Tab tornando alla pagina principale.
  5. Testa con NVDA e Firefox. Apri NVDA, vai alla pagina in Firefox e usa Tab per spostarti tra gli elementi interattivi. Presta attenzione al fatto che NVDA legga un nuovo elemento ogni volta che premi Tab o sembri invece tornare in loop sullo stesso elemento. Se Tab non fa avanzare il focus oltre un componente, si tratta di una trappola da tastiera.
  6. Testa con VoiceOver e Safari su macOS. Attiva VoiceOver (Command + F5), apri la pagina in Safari e usa il tasto Tab per navigare. Conferma che VoiceOver annunci un nuovo elemento a ogni pressione di Tab e che il focus non rimanga mai bloccato in un’area da cui non puoi uscire.
  7. Testa con JAWS e Chrome. Apri JAWS, vai alla pagina in Chrome e usa Tab per navigare in tutti i componenti interattivi. Testa in modo specifico qualsiasi componente che utilizzi una gestione del focus guidata da JavaScript, poiché JAWS interagisce con l’albero di accessibilità in modi che possono rivelare trappole non visibili con il solo test visivo.
  8. Verifica la presenza di meccanismi di uscita non standard. Se un componente richiede un tasto diverso da Tab, Shift+Tab o Escape per uscire, verifica che la pagina comunichi chiaramente questo requisito all’utente — ad esempio tramite istruzioni a schermo, un tooltip o un annuncio in una regione ARIA live quando il focus entra nel componente.

Come Correggere

Finestra di Dialogo Modale Senza Gestione di Escape — Non Corretto

<!-- Modal opens but has no Escape key handler and no close button reachable by keyboard -->
<div id='modal' role='dialog' aria-modal='true' aria-labelledby='modal-title'>
  <h2 id='modal-title'>Confirm Your Order</h2>
  <p>Are you sure you want to place this order?</p>
  <button onclick='submitOrder()'>Confirm</button>
  <!-- No close button, no Escape key listener -- keyboard users are trapped -->
</div>

Finestra di Dialogo Modale Senza Gestione di Escape — Corretto

<!-- Modal with proper focus trap, Escape handler, and accessible close button -->
<div id='modal' role='dialog' aria-modal='true' aria-labelledby='modal-title'>
  <h2 id='modal-title'>Confirm Your Order</h2>
  <p>Are you sure you want to place this order?</p>
  <button onclick='submitOrder()'>Confirm</button>
  <!-- Close button is reachable by Tab and allows keyboard users to exit -->
  <button id='modal-close' onclick='closeModal()' aria-label='Close dialog'>Cancel</button>
</div>

<script>
  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
      closeModal(); // Escape key closes the modal and returns focus to trigger
    }
  });

  function closeModal() {
    document.getElementById('modal').hidden = true;
    document.getElementById('modal-trigger').focus(); // Return focus to opener
  }
</script>

Menu a Discesa Personalizzato che Intercetta Tutti gli Eventi del Tasto Tab — Non Corretto

<!-- Custom dropdown intercepts all keydown events including Tab, preventing focus from leaving -->
<div id='custom-select' tabindex='0' role='combobox' aria-expanded='true'>
  <ul role='listbox'>
    <li role='option' tabindex='-1'>Option 1</li>
    <li role='option' tabindex='-1'>Option 2</li>
    <li role='option' tabindex='-1'>Option 3</li>
  </ul>
</div>

<script>
  // BUG: This captures ALL keyboard events and calls preventDefault on Tab,
  // meaning the user can never Tab out of this component
  document.getElementById('custom-select').addEventListener('keydown', function(e) {
    e.preventDefault(); // This traps the keyboard
    if (e.key === 'ArrowDown') { /* move focus down */ }
    if (e.key === 'ArrowUp') { /* move focus up */ }
  });
</script>

Menu a Discesa Personalizzato che Intercetta Tutti gli Eventi del Tasto Tab — Corretto

<!-- Correct: Only prevent default for arrow keys used for internal navigation;
     allow Tab and Escape to function normally so users can exit -->
<div id='custom-select' tabindex='0' role='combobox' aria-expanded='false'>
  <ul role='listbox' hidden>
    <li role='option' tabindex='-1'>Option 1</li>
    <li role='option' tabindex='-1'>Option 2</li>
    <li role='option' tabindex='-1'>Option 3</li>
  </ul>
</div>

<script>
  document.getElementById('custom-select').addEventListener('keydown', function(e) {
    if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
      e.preventDefault(); // Only prevent default for internal navigation keys
      // move focus between options
    }
    if (e.key === 'Escape' || e.key === 'Tab') {
      // Do NOT call preventDefault -- allow Tab and Escape to propagate
      // so the browser can move focus away from this component naturally
      closeDropdown();
    }
  });
</script>

Iframe di Terze Parti Incorporato Senza Percorso di Uscita — Non Corretto

<!-- An embedded chat widget iframe that absorbs all Tab keypresses
     and never returns focus to the parent page -->
<iframe
  src='https://example-chat-widget.com/embed'
  title='Customer support chat'
  width='350'
  height='500'>
</iframe>
<!-- The iframe's internal JavaScript consumes Tab events, trapping users inside it -->

Iframe di Terze Parti Incorporato Senza Percorso di Uscita — Corretto

<!-- Use a button to open the chat in a new window rather than embedding
     an iframe that may trap keyboard users -->
<button
  id='open-chat'
  onclick='window.open("https://example-chat-widget.com", "_blank", "noopener")'>
  Open Customer Support Chat (opens in new window)
</button>

<!-- If an iframe must be used, add a visible skip link before it
     so keyboard users can bypass it if they choose -->
<a href='#after-chat-widget' class='skip-link'>Skip chat widget</a>
<iframe
  src='https://example-chat-widget.com/embed'
  title='Customer support chat'
  width='350'
  height='500'>
</iframe>
<span id='after-chat-widget' tabindex='-1'></span>

Errori Comuni

  • Chiamare event.preventDefault() all’interno di un listener keydown senza limitarlo a tasti specifici — applicare preventDefault() a tutti gli eventi da tastiera su un componente focalizzabile blocca il funzionamento di Tab e Shift+Tab, creando istantaneamente una trappola da tastiera. Limita sempre preventDefault() solo ai tasti specifici che il tuo componente deve gestire internamente (come i tasti freccia per le listbox).
  • Costruire una finestra di dialogo modale che imposta il focus al suo interno ma non fornisce un gestore del tasto Escape o un pulsante di chiusura — gli sviluppatori spesso implementano correttamente la parte di ingresso del focus nel pattern del modale ma dimenticano che il contenimento del focus all’interno di un modale è accettabile solo se esiste sempre un’uscita accessibile da tastiera. Ogni modale deve gestire il tasto Escape e includere un pulsante di chiusura raggiungibile con Tab.
  • Usare tabindex='-1' su un elemento contenitore per impedirgli di apparire nell’ordine di tabulazione, pur consentendo a JavaScript di spostare il focus al suo interno in modo programmatico — quando il focus viene spostato in un elemento con tabindex='-1' tramite element.focus(), non esiste una destinazione naturale per il Tab per uscirne, il che può lasciare l’utente bloccato se non viene implementata un’ulteriore gestione da tastiera.
  • Incorporare widget di terze parti (chat, mappe, video) senza verificarli per comportamenti di trappola da tastiera — i fornitori non costruiscono sempre i loro widget incorporati in modo che siano accessibili da tastiera. I proprietari dei siti restano responsabili di tutti i contenuti sulle loro pagine, inclusi gli embed di terze parti. Testa sempre manualmente i componenti incorporati e, se intrappolano gli utenti da tastiera, avvolgili con un link di salto o sostituiscili con un’alternativa sicura per la tastiera.
  • Implementare una trappola di focus per un modale o un cassetto laterale ma non rilasciare la trappola quando il componente si chiude — se il JavaScript che limita il focus non viene correttamente ripulito quando il modale si chiude, può continuare a intercettare gli eventi Tab e intrappolare l’utente sul livello ormai invisibile.
  • Usare CSS visibility: hidden o display: none per nascondere il pulsante di chiusura di una finestra di dialogo per motivi di design visivo senza fornire un’uscita alternativa da tastiera — se il pulsante di chiusura è nascosto visivamente ma non rimosso dall’albero di accessibilità, gli utenti di screen reader possono ancora trovarlo; ma se è nascosto anche dall’albero di accessibilità, potrebbe non esserci alcuna uscita. Verifica che tutti i meccanismi di chiusura siano operabili da tastiera anche se stilizzati visivamente in modo discreto.
  • Costruire componenti di autocompletamento o suggerimento in tempo reale personalizzati che aprono un elenco di suggerimenti e poi instradano tutte le pressioni del tasto Tab al ciclo tra i suggerimenti invece che all’uscita — gli utenti dovrebbero poter premere Escape per chiudere l’elenco di suggerimenti e poi Tab per passare al campo del modulo successivo. I widget di autocompletamento che reindirizzano Tab alla navigazione interna violano questo criterio.
  • Dimenticare di testare gli editor di testo avanzato (editor WYSIWYG come TinyMCE, CKEditor o Quill) — questi componenti gestiscono internamente la propria interazione da tastiera e sono una fonte frequente di trappole da tastiera. Conferma sempre che premere Escape o una sequenza di tasti documentata consenta di uscire dall’editor e riporti il focus al normale ordine di tabulazione della pagina.
  • Dare per scontato che, poiché un componente utilizza elementi HTML nativi, non possa creare una trappola da tastiera — un elemento <select> all’interno di un form che utilizza JavaScript per sovrascrivere il suo evento blur può comunque intrappolare il focus. L’uso di HTML semantico non garantisce l’assenza di trappole da tastiera quando vi si sovrappone una gestione personalizzata degli eventi JavaScript.
  • Non fornire documentazione a schermo quando è richiesto un tasto non standard per uscire da un componente — WCAG 2.1.2 consente esplicitamente componenti che richiedono tasti non standard per uscire, a condizione che l’utente sia informato. Se il tuo widget richiede la pressione di F6 o di una combinazione di tasti personalizzata per uscire, devi comunicarlo chiaramente all’utente, idealmente tramite istruzioni visibili adiacenti al componente o un annuncio in una regione ARIA live quando il focus entra.

Relazione con le Normative di Accessibilità della Turchia

La Circolare Presidenziale 2025/10 della Turchia, pubblicata nella Gazzetta Ufficiale n. 32933 il 21 giugno 2025, stabilisce requisiti vincolanti di accessibilità digitale per un’ampia gamma di soggetti pubblici e privati che operano in Turchia. La circolare impone la conformità a standard di accessibilità web riconosciuti a livello internazionale — allineandosi a WCAG 2.1 Livello AA come base, che comprende tutti i criteri di Livello A, incluso WCAG 2.1.2 Nessuna trappola da tastiera.

WCAG 2.1.2 è un criterio di Livello A, che rappresenta il livello minimo di conformità. In base alla circolare, la conformità di Livello A è obbligatoria per tutti i soggetti interessati. Le istituzioni pubbliche sono tenute a raggiungere questa conformità entro un anno dalla pubblicazione della circolare, mentre ai soggetti del settore privato sono concessi due anni per adeguarsi.

I soggetti coperti dalla circolare sono numerosi e includono istituzioni pubbliche e organi di governo a tutti i livelli, piattaforme di e-commerce e operatori di marketplace online, banche e istituzioni di servizi finanziari, ospedali e fornitori di servizi sanitari, società di telecomunicazioni con 200,000 o più abbonati, agenzie di viaggio, società di trasporto privato e scuole private autorizzate dal Ministero dell’Istruzione Nazionale (MoNE). Ciò significa che non affrontare le trappole da tastiera su un sito web o un’applicazione web gestiti da uno qualsiasi di questi soggetti costituisce una violazione diretta delle normative obbligatorie di accessibilità della Turchia.

Data la diffusione delle trappole da tastiera nelle applicazioni web complesse — in particolare nei portali di online banking, nei sistemi di prenotazione di appuntamenti ospedalieri, nei flussi di checkout dell’e-commerce e nelle pagine di gestione degli account delle telecomunicazioni — WCAG 2.1.2 merita particolare attenzione nel contesto della conformità turca. Si tratta esattamente dei tipi di interfacce ricche di interazioni, guidate da JavaScript, che più probabilmente contengono widget personalizzati, finestre di dialogo modali e embed di terze parti che possono intrappolare involontariamente gli utenti da tastiera.

Le organizzazioni soggette alla circolare dovrebbero considerare il test delle trappole da tastiera come una parte non negoziabile del loro processo di audit di accessibilità. Poiché gli strumenti automatizzati non possono rilevare in modo affidabile le trappole da tastiera, i soggetti interessati devono investire in test manuali da tastiera condotti da specialisti di accessibilità qualificati, idealmente includendo utenti con disabilità, come parte del loro percorso verso la conformità. Non correggere le trappole da tastiera identificate durante l’audit rappresenta non solo un rischio legale ai sensi della circolare, ma anche una barriera significativa all’accesso per gli utenti con disabilità motorie e visive che dipendono dalla navigazione da tastiera per utilizzare i servizi digitali.