Modais sem biblioteca: o elemento dialog
Durante anos, pôr um modal numa página significava escolher uma biblioteca — ou reescrever à mão o mesmo conjunto de problemas: o fundo escurecido, o foco preso lá dentro, o Escape a fechar, o scroll da página por trás.
O elemento <dialog> traz isso tudo de origem, e está em todos os browsers atuais desde 2022.
1. O mínimo
<dialog id="aviso">
<p>Tem a certeza que quer apagar?</p>
<form method="dialog">
<button value="nao">Cancelar</button>
<button value="sim">Apagar</button>
</form>
</dialog>const aviso = document.querySelector('#aviso');
aviso.showModal();
aviso.addEventListener('close', () => {
console.log(aviso.returnValue); // 'sim' ou 'nao'
});O method="dialog" num formulário fecha o diálogo ao submeter e guarda o valor do botão no returnValue. Sem uma linha de JavaScript para tratar dos botões.
2. O que o showModal faz e o open não
Prende o foco dentro do diálogo — o Tab não sai de lá.
Torna inerte o resto da página: nada por trás é clicável.
Fecha com a tecla Escape.
Desenha o fundo, que se estiliza com
::backdrop.
O atributo open no HTML, ou o método show(), abrem o diálogo sem nada disto — servem para painéis não modais. Se quer um modal a sério, é sempre showModal().
3. Estilo
dialog {
border: none;
border-radius: 8px;
padding: 1.5rem;
max-width: 32rem;
}
dialog::backdrop {
background: rgb(0 0 0 / 0.5);
}
/* Fechado, não ocupa espaço nenhum: o browser trata disso */
dialog:not([open]) {
display: none;
}4. Fechar ao clicar fora
É a única coisa que não vem incluída. O clique no fundo tem o próprio diálogo como alvo, o que dá uma verificação de duas linhas:
aviso.addEventListener('click', (evento) => {
if (evento.target === aviso) aviso.close('nao');
});Repare que isto é uma escolha, e nem sempre é a certa: num formulário meio preenchido, fechar com um clique ao lado é perder trabalho.