The .modal component uses the CSS checkbox toggle pattern —
the same interactivity model used across the framework for menus, dropdowns and accordions.
A hidden <input type="checkbox"> with class .modal-state holds the
open/closed state, a <label> pointing at that checkbox acts as the trigger, and the
:checked pseudo-class drives the visibility of the .modal overlay. No build
step, no framework JavaScript, no theme switcher — just CSS custom properties and native browser behavior.
Three pieces sit next to each other in the DOM: the checkbox
(.modal-state), the label that toggles it, and the .modal element itself.
The checkbox and the .modal must be adjacent siblings — the framework relies on the
adjacent-sibling selector .modal-state:checked + .modal to reveal the dialog.
Three ways to close: the <label> wrapping .modal__close (an X built
from CSS pseudo-elements, no icon asset needed), a <label> over .modal__bg
(click-outside-to-close), or any other <label for="modal-id"> placed inside the modal
body — handy for a "Cancel" button.
The minimum viable modal — a title, some copy, and a close control.
This is a basic modal built entirely with framework classes: .modal,
.modal-state, .modal__inner, and .modal__close.
Click the background, the X, or the button below to close it.
<label for="modal-basic" class="button">Open basic modal</label>
<input class="modal-state" id="modal-basic" type="checkbox" />
<div class="modal">
<label class="modal__bg" for="modal-basic"></label>
<div class="modal__inner">
<label for="modal-basic" class="modal__close"></label>
<h3 class="bold">Welcome</h3>
<p class="dark">Modal body copy goes here.</p>
<label for="modal-basic" class="button bg-color-1 white">Got it</label>
</div>
</div>
Pairs a semantic icon with .bg-danger / outline buttons for a destructive-action confirmation.
This action cannot be undone. All blocks, pages, and assets tied to this project will be permanently removed.
<label for="modal-confirm" class="button bg-danger white">Delete project</label>
<input class="modal-state" id="modal-confirm" type="checkbox" />
<div class="modal">
<label class="modal__bg" for="modal-confirm"></label>
<div class="modal__inner center">
<label for="modal-confirm" class="modal__close"></label>
<svg viewBox="0 0 24 24" class="icon-danger-fill icon-ml">...</svg>
<h3 class="bold">Delete this project?</h3>
<p class="dark">This action cannot be undone...</p>
<div class="centered-row gap-1 m-t-2">
<label for="modal-confirm" class="button">Cancel</label>
<label for="modal-confirm" class="button bg-danger white">Yes, delete</label>
</div>
</div>
</div>
Same structure, swapped icon and accent color — useful after a completed action.
Your page is now live on cdn.cssvars.com.
Modals can host real form controls — .form-group and .form-control work unchanged inside .modal__inner.
One email a month, no spam.
| Class | Applied to | Purpose |
|---|---|---|
.modal-state |
<input type="checkbox"> |
Hidden checkbox that holds open/closed state. Must be the element immediately before .modal. |
.modal |
<div> |
Full-viewport, fixed-position overlay. Hidden by default (opacity:0; visibility:hidden), revealed when its preceding .modal-state is :checked. |
.modal__bg |
<label> |
Full-size click target layered behind .modal__inner. As a <label for="...">, clicking it unchecks the state and closes the modal. |
.modal__inner |
<div> |
The visible dialog panel — centered, 50%×50% on desktop, 90%×90% under 768px. Uses --panel-bg, --panel-radius, --panel-padding, --panel-border, --panel-shadow tokens. |
.modal__close |
<label> |
Positioned top-right X control, drawn from two rotated CSS pseudo-elements — no icon file required. |
.modal-state:checked + .modal is an adjacent-sibling selector, so the checkbox must come directly before the .modal element — nothing (not even a comment-adjacent wrapper) can sit between them.<label for="...">, not a button with an onclick. Open triggers, the background, the close X, and in-body "Cancel"/"Done" controls are all labels pointing at the same checkbox id..modal-state checkbox its own id and match every corresponding <label for="...">" to it..modal__inner ships at a fixed 50%×50% (90%×90% on mobile) — there's currently no .modal-sm / .modal-lg modifier in cssvars.css. Constrain width by wrapping content, not by inventing new classes.<label> elements — a "Subscribe" or "Delete" action that performs a real operation should remain a <button> or <a>, as in the form modal above.Built with love by Kim Majali, EITO team, and contributors.