dialog
Contrassegna un contenitore come finestra di dialogo modale o non modale. Si consiglia di utilizzare l'elemento nativo <dialog> con showModal() — gestisce gratuitamente il trapping del focus, il top-layer e la chiusura con Escape. Si ricorra a role="dialog" solo quando l'elemento nativo è impossibile da impiegare.
Quando utilizzarlo
Si utilizzi <dialog> aperto tramite .showModal(). L’elemento nativo è supportato da tutti i browser correnti e gestisce autonomamente lo sfondo inerte, il focus trap, la chiusura con Escape, l’hook di stile ::backdrop e il rendering nel top-layer. Consente di risparmiare circa 200 righe di JavaScript fragile.
Si ricorra a role="dialog" su un <div> solo quando:
- Si supportano browser più vecchi di Chrome 37 / Firefox 98 / Safari 15.4 (improbabile nel 2026).
- Il design richiede una finestra di dialogo che non può risiedere nel top-layer (caso raro).
- Si sta correggendo un modal personalizzato inaccessibile durante un refactoring.
Ogni finestra di dialogo DEVE avere un nome accessibile (aria-labelledby che punta a un’intestazione visibile è il pattern più efficace). Le finestre di dialogo modali richiedono inoltre aria-modal="true".
Contratto tastiera + focus
Secondo il pattern dialog (modal) dell’APG:
- All’apertura, il focus si sposta sul primo elemento focusable all’interno della finestra di dialogo (spesso il pulsante di chiusura o il campo di input principale).
- Tab e Shift+Tab spostano il focus ESCLUSIVAMENTE all’interno della finestra di dialogo — un «focus trap». Tab dall’ultimo elemento ritorna al primo; Shift+Tab dal primo ritorna all’ultimo.
- Escape chiude la finestra di dialogo.
- Alla chiusura, il focus ritorna all’elemento che ha aperto la finestra di dialogo. Salvare e ripristinare il focus è imprescindibile: gli utenti che perdono il proprio punto di riferimento non hanno un’ancora.
- Il resto della pagina è
inert(oppurearia-hidden="true"+ non-focusable come fallback) mentre la finestra di dialogo è aperta.
Errori comuni
- Modal personalizzato senza focus trap. Tab esce dalla finestra di dialogo e si sposta dietro di essa; gli utenti perdono il contesto.
- Focus non ripristinato sull’elemento trigger alla chiusura. Il successivo Tab atterra sul corpo del documento.
- Il contenuto in background rimane accessibile via Tab anche se è visivamente nascosto dietro la finestra di dialogo.
- Nessun nome accessibile. La finestra di dialogo si apre e lo screen reader annuncia solo «dialog».
- Modal personalizzato senza
aria-modal="true"— le tecnologie assistive lo trattano come contenuto inline. - Escape chiude la finestra di dialogo, ma questa è renderizzata tramite un portal che perde il focus da tastiera durante l’animazione di chiusura.
Esempio
<!-- Preferito -->
<dialog id="confirm">
<h2>Delete this draft?</h2>
<p>This cannot be undone.</p>
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="delete" autofocus>Delete</button>
</form>
</dialog>
<script>
document.getElementById('confirm').showModal();
</script>
<!-- Quando <dialog> è impossibile -->
<div role="dialog" aria-modal="true" aria-labelledby="dlgTitle">
<h2 id="dlgTitle">Edit profile</h2>
…
</div>