Caixa de diálogo modal
Use o elemento dialog nativo para implementar uma caixa de diálogo de confirmação acessível.
É possível editar, executar e salvar este exemplo após ativar JavaScript. O código-fonte fixo é o seguinte:
<!doctype html>
<html lang="pt-BR" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Caixa de diálogo modal</title>
<style>
* { box-sizing: border-box; }
body {
min-height: 100vh;
margin: 0;
display: grid;
place-items: center;
padding: 24px;
color: #2a241f;
font-family: "Avenir Next", "Microsoft YaHei", sans-serif;
background: #efe9df;
background-image: radial-gradient(#c7baaa 1px, transparent 1px);
background-size: 22px 22px;
}
.card {
width: min(680px, 100%);
padding: clamp(28px, 6vw, 58px);
border: 1px solid #d8cbbb;
border-radius: 4px 38px 4px 38px;
background: #fffdf8;
box-shadow: 16px 18px 0 #d8cbbb;
}
.number { display: block; color: #9a4c33; font: 700 13px/1 Georgia, serif; letter-spacing: .18em; }
h1 { max-width: 520px; margin: 16px 0 12px; font: 700 clamp(38px, 8vw, 68px)/.98 Georgia, "STSong", serif; }
.card p { max-width: 520px; margin: 0 0 30px; color: #6f6359; line-height: 1.75; }
button { border: 0; font: inherit; font-weight: 750; cursor: pointer; }
.open-button { padding: 14px 22px; border-radius: 999px; color: #fffdf8; background: #2a241f; box-shadow: 0 8px 0 #9a4c33; transition: transform .15s ease, box-shadow .15s ease; }
.open-button:active { transform: translateY(5px); box-shadow: 0 3px 0 #9a4c33; }
button:focus-visible { outline: 3px solid #d27853; outline-offset: 3px; }
dialog {
width: min(470px, calc(100% - 32px));
padding: 0;
border: 0;
border-radius: 28px;
color: #2a241f;
background: #fffdf8;
box-shadow: 0 24px 90px rgba(33, 24, 19, .35);
}
dialog::backdrop { background: rgba(35, 27, 21, .68); backdrop-filter: blur(5px); }
dialog[open] { animation: rise .28s ease both; }
.dialog-body { padding: 34px; }
.icon { display: grid; width: 54px; height: 54px; place-items: center; border-radius: 50%; color: #9a4c33; font-size: 25px; background: #f6dfd5; }
h2 { margin: 20px 0 8px; font: 700 30px/1.15 Georgia, "STSong", serif; }
.dialog-body p { margin: 0; color: #706258; line-height: 1.65; }
.actions { display: flex; justify-content: flex-end; gap: 12px; padding: 18px 34px 28px; }
.actions button { padding: 12px 18px; border-radius: 999px; }
.cancel { color: #4f443c; background: #eee8df; }
.confirm { color: white; background: #9a4c33; }
.status { min-height: 24px; margin-top: 24px !important; color: #9a4c33 !important; font-weight: 700; }
@keyframes rise { from { opacity: 0; transform: translateY(24px) scale(.96); } }
@media (prefers-reduced-motion: reduce) { dialog[open] { animation: none; } }
</style>
</head>
<body>
<main class="card">
<span class="number">COMPONENT 02</span>
<h1>Uma confirmação clara</h1>
<p>O dialog nativo gerencia automaticamente o foco e a interação com o fundo. Clique no botão para ver o fluxo de confirmação ou pressione Esc para fechar.</p>
<button id="openDialog" class="open-button" type="button">Abrir diálogo</button>
<p id="status" class="status" role="status" aria-live="polite"></p>
</main>
<dialog id="confirmDialog" aria-labelledby="dialogTitle" aria-describedby="dialogDescription">
<div class="dialog-body">
<div class="icon" aria-hidden="true">✓</div>
<h2 id="dialogTitle">Confirmar o salvamento deste design?</h2>
<p id="dialogDescription">Depois de salvar, a nova versão substituirá o rascunho atual. Você ainda pode recuperar a versão antiga no histórico.</p>
</div>
<div class="actions">
<button class="cancel" type="button" data-dialog-result="cancel">Não salvar por enquanto</button>
<button class="confirm" type="button" data-dialog-result="confirm">Salvar confirmações</button>
</div>
</dialog>
<script>
const dialog = document.querySelector('#confirmDialog');
const status = document.querySelector('#status');
document.querySelector('#openDialog').addEventListener('click', () => {
dialog.returnValue = '';
dialog.showModal();
});
document.querySelectorAll('[data-dialog-result]').forEach(button => {
button.addEventListener('click', () => dialog.close(button.dataset.dialogResult));
});
dialog.addEventListener('close', () => {
status.textContent = dialog.returnValue === 'confirm' ? 'O design foi salvo com segurança.' : 'A operação foi cancelada e nenhum conteúdo foi alterado.';
});
</script>
</body>
</html>