Boîte de dialogue modale
Utiliser l’élément dialog natif pour créer une boîte de dialogue de confirmation accessible.
Après activation de JavaScript, ce cas peut être modifié, exécuté et enregistré. Code source fixe ci-dessous :
<!doctype html>
<html lang="fr" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Boîte de dialogue modale</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>Une confirmation claire</h1>
<p>Le dialogue natif dialog gère automatiquement le focus et les interactions avec l’arrière-plan. Cliquez sur le bouton pour voir le flux de confirmation, ou appuyez sur Esc pour fermer.</p>
<button id="openDialog" class="open-button" type="button">Ouvrir la boîte de dialogue</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">Confirmer l’enregistrement de ce design ?</h2>
<p id="dialogDescription">Après l’enregistrement, la nouvelle version remplacera le brouillon actuel. Vous pourrez toujours retrouver l’ancienne version dans l’historique.</p>
</div>
<div class="actions">
<button class="cancel" type="button" data-dialog-result="cancel">Ne pas enregistrer pour le moment</button>
<button class="confirm" type="button" data-dialog-result="confirm">Confirmer l’enregistrement</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' ? 'La conception a été enregistrée en toute sécurité.' : 'L’opération a été annulée, aucune modification n’a été apportée.';
});
</script>
</body>
</html>