React
Dialog shadcn accessibile
Ogni DialogContent vuole un DialogTitle, anche nascosto, e una descrizione o una dichiarazione esplicita della sua assenza. Radix fa il resto.
In sintesi
- Un DialogContent senza DialogTitle genera un avviso in console e un dialog senza nome accessibile.
- Il titolo può essere invisibile: si nasconde con VisuallyHidden, non si omette.
- Focus trap, tasto Esc e ripristino del focus arrivano da Radix, con licenza MIT.
Risposta breve: ogni DialogContent deve contenere un DialogTitle, anche se il titolo non si vede. Radix collega quel titolo al dialog tramite aria-labelledby, e senza di lui il dialog resta senza nome per lo screen reader.
Il minimo che regge
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export function DeleteDialog({ name }: { name: string }) {
return (
Elimina
Eliminare {name}?
Non si può annullare.
Annulla
Conferma
);
}
Il pulsante che apre il dialog conserva il testo, quindi ha già un nome accessibile: aria-label qui sarebbe rumore. Il asChild su DialogTrigger serve a non aggiungere un button dentro un altro button, che è il modo più rapido per rompere la navigazione da tastiera.
Cosa arriva gratis
- Focus trap: il tab resta dentro il dialog finché è aperto, e il focus torna al trigger alla chiusura.
- Esc e click fuori: le due uscite predefinite funzionano, e
onEscapeKeyDownpermette di bloccarle quando servono. - Attributi:
role="dialog",aria-modale i riferimenti a titolo e descrizione li scrive Radix. - Scroll di sfondo: il body smette di scorrere, senza il salto che si vede quando lo blocchi con
overflow: hidden.
Il titolo che non si vede
Un dialog di sole azioni può non avere un titolo visibile, ma il titolo serve lo stesso: si monta DialogTitle dentro un contenitore che lo nasconde visivamente, lasciandolo nel DOM. Il testo resta leggibile dallo screen reader e il riferimento aria-labelledby continua a puntare a un nodo esistente.
Le trappole ricorrenti
Un DropdownMenu dentro un DialogContent porta il menu in un portal esterno, e il click fuori dal dialog chiude tutto: la sequenza è descritta in il dialog si chiude da un dropdown. Un dialog dentro un altro dialog richiede attenzione al focus, perché l'ultimo aperto deve prendere il controllo.
Il comando
npx shadcn@latest add dialog
Record vivi nel catalogo
I dialog già pubblicati mostrano le varianti: dialog-01 per la conferma, la categoria blocchi dialog per gli altri casi, e la libreria shadcn per il componente base. Ogni record indica licenza e sorgente.
La limitazione
Un dialog senza testo descrittivo chiede di dichiarare l'assenza del riferimento, altrimenti la console avvisa a ogni apertura. Il componente non può indovinare se la descrizione sia utile: quella decisione resta al contenuto, e nessun test automatico la prende al posto tuo. La checklist è in componenti React accessibili.
Dove continuare
L'errore del titolo mancante è analizzato in DialogContent richiede DialogTitle; il ruolo di ARIA è spiegato in che cos'è ARIA; l'abuso opposto è in aria-label sui bottoni. Per una verifica completa leggi come fare un audit di accessibilità.
Domande frequenti
Posso omettere DialogTitle se il titolo non si vede?
No. Il titolo può essere nascosto visivamente, ma deve esistere nel DOM, perché Radix lo usa come nome accessibile del dialog tramite aria-labelledby.
Perché compare l'avviso su DialogContent?
Perché manca un DialogTitle oppure una DialogDescription, e Radix segnala il riferimento assente. Aggiungi i due componenti, o dichiara esplicitamente che la descrizione non c'è.
Il dialog sposta il focus da solo?
Sì. All'apertura il focus va nel contenuto, resta intrappolato finché il dialog è aperto e torna al trigger alla chiusura. È il comportamento di Radix, non codice da scrivere.
Serve aria-label sul dialog?
No, se c'è un DialogTitle: il nome arriva da lì. Un aria-label in più non aggiunge nulla, e se il titolo esiste già i due testi possono divergere.
Il dialog va bene anche per una conferma distruttiva?
Sì, purché il pulsante distruttivo sia chiaro nel testo e non solo nel colore, e il titolo dica cosa viene eliminato. Il focus iniziale resta consigliato sulla conferma, non sull'azione distruttiva.