This example demonstrates how to build a fully functional dialog/modal using only HTML and CSS.
<!-- HTML Structure for the Dialog -->
<input type="checkbox" id="dialog-toggle" class="hidden">
<label for="dialog-toggle" class="dialog-open">Open</label>
<div class="dialog-backdrop">
<dialog open>
<label for="dialog-toggle" class="dialog-close" aria-label="Close">×</label>
<h2>Dialog Title</h2>
<p>
This dialog uses a pure CSS backdrop <br>
element to provide blur and overlay, alongside the <dialog> element.
</p>
</dialog>
</div>
/* CSS Styles for the Dialog */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f5f5f5;
font-family: Arial, sans-serif;
}
.hidden {
display: none;
}
.dialog-open {
padding: 0.5rem 1rem;
border: none;
border-radius: 0.375rem;
cursor: pointer;
background: #3b82f6;
color: #fff;
}
.dialog-backdrop {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(12px);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
#dialog-toggle:checked ~ .dialog-backdrop {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
dialog {
margin: auto;
padding: 2rem;
border: none;
border-radius: 0.5rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
background: #fff;
opacity: 0;
transform: scale(0.95);
transition: opacity 0.3s ease, transform 0.3s ease;
}
#dialog-toggle:checked ~ .dialog-backdrop dialog {
opacity: 1;
transform: scale(1);
}
.dialog-close {
position: absolute;
top: 0.5rem;
right: 0.5rem;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
- HTML Input Toggle: The checkbox input serves as a state toggle.
- CSS Sibling Selector: The
~
sibling combinator applies styles to the.dialog-backdrop
and<dialog>
based on the input's state. - Accessibility: Semantic
<dialog>
element andaria-label
improve user accessibility.