Dialogs
Native HTML <dialog>
elements with optional transition animation styles and light-dismiss.
Examples (anchor)
The dialogs use a method and script (see source below) adapted from Fun with the dialog element by Mark Otto that uses data-attributes with unique IDs to provide the opening and closing functionality.
Example HTML
<button data-dialog="#dialog">Basic</button>
<dialog id="dialog">
<h2>Basic</h2>
<p>Uses the script for the opening and closing buttons.</p>
<button class="close-dialog">Close</button>
</dialog>
To enable clicking on the background outside the dialog to close it place <div class="close-dialog"></div>
as the last child in the dialog.
Example HTML
<button data-dialog="#dialog-light-dismiss">Basic light-dismiss</button>
<dialog id="dialog-light-dismiss">
<h2>Light-dismiss</h2>
<p>Uses the script for opening, closing button and light-dismiss.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
Form method (anchor)
If required a form method="dialog"
button can also be combined with the technique for closing dialogs containing form content.
Example HTML
<button data-dialog="#dialog-form">Form method</button>
<dialog id="dialog-form">
<h2>Form method</h2>
<p>Uses the script for opening and form method button for closing.</p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
<button data-dialog="#dialog-form-light-dismiss">Form method with light-dismiss</button>
<dialog id="dialog-form-light-dismiss">
<h2>Form method with light-dismiss</h2>
<p>Uses the script for opening and light-dismiss, and form method button for closing button.</p>
<form method="dialog">
<button>Close</button>
</form>
<div class="close-dialog"></div>
</dialog>
Offcanvas (anchor)
Example HTML
<button data-dialog="#dialog-offcanvas-start">Offcanvas start</button>
<dialog id="dialog-offcanvas-start" class="dialog-offcanvas-start">
<h2>Offcanvas start</h2>
<p>The quick brown fox jumps over the lazy dog followed by five boxing wizards jumping quickly.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
<button data-dialog="#dialog-offcanvas-end">Offcanvas end</button>
<dialog id="dialog-offcanvas-end" class="dialog-offcanvas-end">
<h2>Offcanvas end</h2>
<p>The quick brown fox jumps over the lazy dog followed by five boxing wizards jumping quickly.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
Transition (anchor)
The optional transition animation style is compiled with @media (prefers-reduced-motion: no-preference)
to respect a users preferences. If included the default .25s transition timing can be customized inline using the CSS variable --dialog-transition
.
Examples HTML
The dialog animation is enabled for this website so the 'No transition' example uses the variable to remove the default .25s transition included to demonstrate default non-animated dialogs.
<button data-dialog="#default-transition">No transition</button>
<dialog id="default-transition" style="--dialog-transition: 0s;">
<h2>Heading basic</h2>
<p>The quick brown fox jumps over the lazy dog.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
<button data-dialog="#transition-enabled">Enabled (default .25s)</button>
<dialog id="transition-enabled">
<h2>Heading basic</h2>
<p>The quick brown fox jumps over the lazy dog.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
<button data-dialog="#transition-custom">Enabled (custom 1.5s)</button>
<dialog id="transition-custom" style="--dialog-transition: 1.5s;">
<h2>Heading basic</h2>
<p>The quick brown fox jumps over the lazy dog.</p>
<button class="close-dialog">Close</button>
<div class="close-dialog"></div>
</dialog>
Fixed light and dark (anchor)
Example HTML
<button data-dialog="#dialog-light" class="btn-light">Light dialog</button>
<dialog id="dialog-light" class="dialog-light">
<h2>Light dialog</h2>
<p>The quick brown fox jumps over the lazy dog.</p>
<button class="close-dialog btn-light">Close</button>
<div class="close-dialog"></div>
</dialog>
<button data-dialog="#dialog-dark" class="btn-dark">Dark dialog</button>
<dialog id="dialog-dark" class="dialog-dark">
<h2>Dark dialog</h2>
<p>The quick brown fox jumps over the lazy dog.</p>
<button class="close-dialog btn-dark">Close</button>
<div class="close-dialog"></div>
</dialog>
Using the module (anchor)
To use the module load the StyleMods scss
directory as follows (changing the path to suit the source files location as required) then include the Sass mixin(s) anywhere below.
@use "stylemods/scss" as *;
@include dialogs-css;
@include dialogs-animation-css;
See customizing for information about using the Sass and CSS variables in the source code below to customize the styles, and Sass variables (on the using StyleMods page) for other ways to use the variables to create custom styles.
Source code (anchor)
dialogs.scss
// ----------------------------------------------------------
// Dialogs
// ----------------------------------------------------------
$dialog-text-color: var(--dialog-text, CanvasText) !default;
$dialog-margin-top: var(--dialog-mt, 1rem) !default;
$dialog-padding-block: var(--dialog-py, 0.75rem) !default;
$dialog-padding-inline: var(--dialog-px, 1rem) !default;
$dialog-border-color: var(--dialog-bd-color, color-mix(in srgb, CanvasText 15%, Canvas)) !default;
$dialog-radius: var(--dialog-radius, 0.125em) !default;
$dialog-background-color: var(--dialog-bg, Canvas) !default;
$dialog-transition: var(--dialog-transition, 0.25s) !default;
$dialog-backdrop: color-mix(in srgb, black 50%, transparent) !default;
@mixin dialogs-css {
:where(dialog) {
color: $dialog-text-color;
block-size: fit-content;
max-block-size: calc(100vh - 2rem);
inline-size: calc((100% - 6px) - 2em);
max-inline-size: var(--dialog-width, fit-content);
margin-block-start: $dialog-margin-top;
padding-block: $dialog-padding-block;
padding-inline: $dialog-padding-inline;
border: 1px solid $dialog-border-color;
border-radius: $dialog-radius;
background-color: $dialog-background-color;
overflow: auto;
overscroll-behavior: contain;
}
dialog div[class="close-dialog"] {
position: fixed;
inset: 0;
z-index: -1;
display: block;
content: "";
}
dialog[open]::backdrop {
background-color: $dialog-backdrop;
}
// Offcanvas
.dialog-offcanvas-start, .dialog-offcanvas-end {
--dialog-width: 24rem;
--dialog-radius: 0;
margin: 0;
block-size: 100dvh;
max-block-size: 100%;
border: none;
}
.dialog-offcanvas-start {
margin-inline-end: auto;
border-inline-end: 1px solid $dialog-border-color;
}
.dialog-offcanvas-end {
margin-inline-start: auto;
border-inline-start: 1px solid $dialog-border-color;
}
} // end dialogs-css
@mixin dialogs-animation-css {
@media screen and (prefers-reduced-motion: no-preference) {
dialog[open] {
transition: $dialog-transition;
opacity: 1;
}
}
@starting-style {
dialog[open] {
opacity: 0;
}
}
.dialog-light {
color-scheme: light;
}
.dialog-dark {
color-scheme: dark;
}
}
dialog.js
let toggler = document.querySelectorAll("[data-dialog]"),
closers = document.querySelectorAll(".close-dialog");
toggler &&
(toggler.forEach(function (e) {
let l = e.getAttribute("data-dialog"),
dt = document.querySelectorAll(l);
e.addEventListener("click", (e) => {
t.forEach(function (e) {
e.showModal();
});
});
}),
closers.forEach(function (e) {
e.addEventListener("click", (l) => {
e.closest("dialog").close();
});
}));