Dialog nativo em HTML: como usar e estilizar modais sem dependências
O elemento dialog resolve foco, backdrop e inertness de forma nativa. Um guia sobre showModal, ::backdrop, @starting-style e quando preferir Popover.

Faz quase dez anos que o HTML ganhou o elemento nativo, e ainda assim a maioria de nós continua reinventando modais com bibliotecas ou div soltas. Um artigo recente de Geoff Graham no CSS-Tricks ("Using and Styling the Dialog Element") revisita o assunto com calma, e vale destrinchar o que ele muda na prática para quem se preocupa com acessibilidade e performance.
show() não é o que você quer
O ponto mais importante do texto é a distinção entre os dois métodos de abertura. O dialog.show() abre o elemento, mas o trata como um popover: sem backdrop, sem posicionamento central e sem fechar com Esc. Na prática, o que quase todo mundo chama de "modal" é o dialog.showModal(), que traz três coisas de graça:
- backdrop (o fundo escurecido)
- posicionamento automático no centro da viewport
- fechamento pela tecla
Esc
Para fechar via UI, existe o método close() (curiosamente, não há um closeModal() correspondente). E dá para fechar sem JavaScript nenhum, usando um com um botão de submit dentro do diálogo. É o tipo de detalhe que reduz superfície de código e bugs.
Inertness: o motivo real de usar showModal()
Aqui está o argumento que sustenta o ângulo de acessibilidade. Quando o diálogo abre em modo modal, o restante da página fica inert automaticamente: nada de seleção de texto, clique, foco ou input atrás dele. Você não vê o atributo inert no markup, mas ele está agindo. Isso significa gestão de foco automática e leitores de tela impedidos de vazar para o conteúdo de fundo, sem uma linha de JS.
Graham reforça uma sutileza de rotulagem: um botão de fechar com um simples X é péssimo para leitores de tela. A recomendação é usar um Fechar modal para o texto anunciado e marcar o ícone com aria-hidden="true". Ele também nota que o botão de fechar recebe foco por padrão ao abrir, o que pode levar a um fechamento acidental com a barra de espaço; se houver um link ou campo dentro do diálogo, considere dar foco inicial a ele via tabindex.
Estilizar exige selecionar o estado certo
Um tropeço comum: aplicar estilos direto em dialog { ... }. O jeito correto, segundo o artigo, é mirar no estado aberto com a pseudo-classe :open:
dialog:open {
background-color: gold;
border: 0;
border-radius: 12px;
}Vale o alerta de suporte: o :open é recente (o Safari 26.5 ganhou suporte no dia em que o texto foi escrito). Para compatibilidade mais ampla, use o seletor de atributo [open] ou a pseudo-classe :modal, que tem especificidade ainda maior. O backdrop, por sua vez, se estiliza com o pseudo-elemento ::backdrop (um blur() leve costuma dar contexto sem esconder tudo). E não sobrescreva o display: o dialog nasce como display: none fechado, e mexer nisso mata a lógica de aberto/fechado.
Impedir scroll do fundo e animar a entrada
O conteúdo atrás do backdrop rola por padrão, o que tira o usuário de contexto. Graham mostra duas soluções. A moderna usa overscroll-behavior: contain no diálogo e no backdrop, mas depende do Chrome 144+ e de tornar o dialog um scroll container com overflow: hidden. A mais compatível e concisa aproveita :has():
body:has(dialog[open]) {
overflow: hidden;
}Para animação de entrada, esbarramos num detalhe do ciclo de vida: como o diálogo sai de display: none, um transition de opacity simples não pega. É preciso a at-rule @starting-style para definir o estado inicial do primeiro frame renderizado. Já View Transitions, segundo o autor, não são um bom caso aqui: como o modal vive na top layer, o fechamento nem sempre produz um par old/new confiável. O híbrido sugerido é view transition na abertura e animação CSS no fechamento, ou simplesmente CSS nos dois lados.
Dialog ou Popover?
A parte que mais interessa a quem decide arquitetura vem de uma citação de Zell Liew: use a Popover API para a maioria dos popovers e a Dialog API só para modais. A diferença está na acessibilidade. Popovers não trazem gestão automática de foco, conexão ARIA nem light dismiss, e ainda exigem um role explícito escolhido a dedo. O diálogo modal, ao contrário, torna os outros elementos inert, prende o foco e bloqueia leitores de tela automaticamente.
Na formulação de Zell: "Popover é um termo guarda-chuva para qualquer popup sob demanda. Dialog é um tipo de popover, o que cria uma nova janela para conter algum conteúdo." A lição prática: não é sobre usar sempre dialog, e sim escolher a API certa para o caso, medindo o custo de acessibilidade que você teria de refazer à mão.
Fonte: CSS-Tricks
Este artigo foi escrito por Carina Ferreira, colunista de front-end do iMasters, um agente de inteligência artificial com revisão editorial humana.









