Components
Dialog
Native dialog modals driven by the Invoker Commands API, with no JavaScript to wire up.
Dialogs use a native <dialog class="dialog">. Open one from any button with
command="show-modal" and commandfor="<id>", and close with command="close". Add
closedby="any" for light-dismiss. Size with data-size.
Default
Loading components…
<button class="button" type="button" command="show-modal" commandfor="dialog-example-1"> Dialog <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="64" y1="192" x2="192" y2="64" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <polyline points="88 64 192 64 192 168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg></button><dialog id="dialog-example-1" class="dialog" closedby="any"> <div class="dialog__content"> <header class="dialog__header"> <h2 class="text-lg font-heading font-strong">Dialog title</h2> <p class="text-muted-foreground"> This dialog was opened using an <a href="https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API" target="_blank" class="text-link" >invoker command</a >. </p> </header> <div class="dialog__body"> <p>Set the size of the dialog with the <code>data-size</code> attribute.</p> </div> <footer class="dialog__footer"> <button class="button" type="button" commandfor="dialog-example-1" command="close"> Cancel </button> <button class="button" data-variant="primary" commandfor="dialog-example-1" command="close"> Accept </button> </footer> </div> <button class="button dialog__close" data-size="icon" data-variant="ghost" type="button" commandfor="dialog-example-1" command="close" > <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="200" y1="56" x2="56" y2="200" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <line x1="200" y1="200" x2="56" y2="56" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button></dialog>/** * _dialog.css — Dialog (.dialog on native <dialog>) * * @layer variables, reset, components * @requires layers.css, _variables.css * @uses <dialog>, ::backdrop — native modal + backdrop * @uses @starting-style + allow-discrete — open/close opacity, transform, overlay * @uses anchor-name, container-type — layout hooks for sized variants * @tokens --dialog-* (@layer variables; sizing tokens in a second variables block) */@layer variables { :root { --dialog-display: grid; --dialog-backdrop-color: var(--shade-900); --dialog-transition-duration: var(--default-transition-duration); --dialog-transition-timing-function: var(--default-transition-timing-function); --dialog-backdrop-transition-duration: calc(var(--dialog-transition-duration) - 100ms); --dialog-backdrop-transition-timing-function: ease; --dialog-backdrop-blur: blur(5px); --dialog-shadow: var(--shadow-lg); --dialog-border: 1px solid var(--border); --dialog-width: min(var(--breakpoint-md), 100% - var(--gutters) * 2); /* Reveal transitions/animations */ --dialog-opacity--start: 0; --dialog-opacity--end: 1; --dialog-scale--start: 0.98; --dialog-scale--end: 1; --dialog-translate--start: 0, 0, 0; --dialog-translate--end: 0, 0, 0; --dialog-transition-delay--start: 0ms; --dialog-transition-delay--end: 150ms; }}/* Sizing tokens — second variables block (overrides --dialog-width above). */@layer variables { :root { --dialog-width: min(50ch, 100% - var(--gap-md) * 2); --dialog-height: fit-content; --dialog-background: var(--card); --dialog-foreground: var(--card-foreground); --dialog-radius: var(--radius-lg); }}@layer reset { /* =========================================================================== DIALOG — native <dialog> open/close animation, sizing, backdrop fade - In the reset layer so the .dialog component styling below wins. =========================================================================== */ /* Prevent body scroll when a dialog inside the preview is open */ /* Dialog animations with spring easing */ :where(dialog) { margin: auto; max-inline-size: calc(100% - var(--gap-md)); max-block-size: calc(100% - var(--gap-md)); border: var(--dialog-border); contain: layout style; opacity: var(--dialog-opacity--start); box-shadow: var(--dialog-shadow); overscroll-behavior: contain; overflow: auto; transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); transition: opacity var(--dialog-transition-duration) var(--dialog-transition-timing-function), transform var(--dialog-transition-duration) var(--dialog-transition-timing-function), padding var(--dialog-transition-duration) var(--dialog-transition-timing-function), block-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), inline-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), overlay var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete, display var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete; transition-delay: var(--dialog-transition-delay--start); } :where(dialog[open]) { transform: translate3d(var(--dialog-translate--end)) scale(var(--dialog-scale--end)); opacity: var(--dialog-opacity--end); transition-delay: var(--dialog-transition-delay--end); @starting-style { transition-delay: var(--dialog-transition-delay--start); transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); opacity: var(--dialog-opacity--start); } } /* Dialog backdrop with smooth fade transition */ :where(dialog)::backdrop { position: fixed; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; opacity: 0; overscroll-behavior: contain; overflow: auto; background-color: var(--dialog-backdrop-color); backdrop-filter: var(--dialog-backdrop-blur); transition: opacity var(--dialog-backdrop-transition-duration) var(--dialog-backdrop-transition-timing-function); } :where(dialog[open])::backdrop { opacity: 1; @starting-style { opacity: 0; } }}@layer zazz.components { .dialog { /* Overrides reset-layer --dialog-shadow (reset > variables) */ --dialog-shadow: var(--shadow-md); inline-size: var(--dialog-width); block-size: var(--dialog-height); background-color: var(--dialog-background); color: var(--dialog-foreground); box-shadow: var(--dialog-shadow); border-radius: var(--dialog-radius); anchor-name: --dialog-root; container-type: inline-size; container-name: dialog; font-size: var(--font-size-md); isolation: isolate; } .dialog[open] { grid-template-rows: minmax(0, 1fr); min-block-size: 0; } .dialog__close { position: absolute; top: var(--gap-xs); right: var(--gap-xs); z-index: 50; } .dialog__close > svg { inline-size: var(--step-4); block-size: var(--step-4); pointer-events: none; justify-content: center; align-items: center; display: flex; padding: 0; } .dialog__content { display: grid; align-self: center; grid-template-rows: auto minmax(0, 1fr) auto; position: relative; min-block-size: 0; overflow: clip; } .dialog__header { display: flex; flex-direction: column; padding-inline: var(--gap-sm); padding-block-start: var(--gap-sm); } /* Sticky top edge */ .dialog__header::after { content: ""; display: block; position: absolute; top: 100%; inline-size: 100%; block-size: var(--gap-md); background: linear-gradient(to top, transparent, var(--dialog-background)); } .dialog__body { display: grid; padding-inline: var(--gap-sm); padding-block: var(--gap-md); min-block-size: 0; min-block-size: var(--gap-xl); overflow-x: clip; overflow-y: auto; scrollbar-gutter: stable both-edges; } .dialog__footer { block-size: fit-content; position: sticky; bottom: 0; display: flex; justify-content: flex-end; align-self: end; flex-shrink: 0; gap: var(--gap-xs); padding: var(--gap-sm); border-top: 1px solid var(--border); background-color: var(--dialog-background); } .dialog[data-size="article"] { --dialog-width: var(--article-md); } .dialog[data-size="container"] { --dialog-width: var(--breakpoint-md); } .dialog[data-size="screen"] { --dialog-width: 100vi; --dialog-height: 100svh; --dialog-radius: 0; --dialog-shadow: none; max-inline-size: 100vi; max-block-size: 100svh; }}With a form
Loading components…
<button class="button" type="button" command="show-modal" commandfor="form-dialog-1"> New project <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="40" y1="128" x2="216" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <line x1="128" y1="40" x2="128" y2="216" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg></button><dialog id="form-dialog-1" class="dialog" closedby="any" data-size="article"> <div class="dialog__content"> <header class="dialog__header"> <h2 class="text-lg font-heading font-strong">New project</h2> <p class="text-muted-foreground"> Add a project to your workspace. You can change these settings later. </p> </header> <form id="f-new-project-1" class="dialog__body flex flex-col gap-md" method="dialog"> <fieldset class="field-group"> <legend class="sr-only">Contact</legend> <div class="grid grid-cols-2 gap-sm"> <div class="field"> <label class="field__label" for="fd-name">Name</label> <input class="input" id="fd-name" name="name" type="text" inputmode="text" placeholder="Ada Lovelace" required /> </div> <div class="field"> <label class="field__label" for="fd-email">Email</label> <input class="input" id="fd-email" name="email" type="email" inputmode="email" required placeholder="you@example.com" autocomplete="email" aria-describedby="fd-email-hint" /> <div class="field__description"> <span class="field__hint" id="fd-email-hint" >We'll only use this to send receipts.</span > <span class="field__error" role="alert">Please enter a valid email address.</span> </div> </div> <label class="field-group col-span-2"> <span class="field__label">Repository</span> <div class="input-group"> <input class="input" type="search" name="repo" id="fd-repo" inputmode="search" placeholder="Search repositories…" /> <span class="input-group__addon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <circle cx="112" cy="112" r="80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <line x1="168.57" y1="168.57" x2="224" y2="224" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </span> </div> </label> </div> </fieldset> <fieldset class="field-group"> <div class="field"> <label class="field__label" for="fd-message">Description</label> <textarea class="textarea" id="fd-message" name="description" inputmode="text" placeholder="What is this project for?" ></textarea> </div> </fieldset> <fieldset class="radio-group"> <legend>Billing</legend> <label class="field" data-orientation="horizontal"> <input class="radio" type="radio" name="billing" value="monthly" /> <span class="field__label">Monthly billing</span> </label> <label class="field" data-orientation="horizontal"> <input class="radio" type="radio" name="billing" value="annual" checked /> <span class="field__label">Annual billing</span> </label> </fieldset> <label class="field" data-orientation="horizontal"> <input type="checkbox" name="terms" required /> <span class="field__label">Accept terms & conditions</span> </label> </form> <footer class="dialog__footer"> <button class="button" type="button" value="cancel" commandfor="form-dialog-1" command="close" > Cancel </button> <button class="button" data-variant="primary" type="submit" form="f-new-project-1" value="save" > Create project </button> </footer> <button class="button dialog__close" data-size="icon" data-variant="ghost" type="button" commandfor="form-dialog-1" command="close" aria-label="Close dialog" > <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <line x1="200" y1="56" x2="56" y2="200" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> <line x1="200" y1="200" x2="56" y2="56" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" /> </svg> </button> </div></dialog>/** * _dialog.css — Dialog (.dialog on native <dialog>) * * @layer variables, reset, components * @requires layers.css, _variables.css * @uses <dialog>, ::backdrop — native modal + backdrop * @uses @starting-style + allow-discrete — open/close opacity, transform, overlay * @uses anchor-name, container-type — layout hooks for sized variants * @tokens --dialog-* (@layer variables; sizing tokens in a second variables block) */@layer variables { :root { --dialog-display: grid; --dialog-backdrop-color: var(--shade-900); --dialog-transition-duration: var(--default-transition-duration); --dialog-transition-timing-function: var(--default-transition-timing-function); --dialog-backdrop-transition-duration: calc(var(--dialog-transition-duration) - 100ms); --dialog-backdrop-transition-timing-function: ease; --dialog-backdrop-blur: blur(5px); --dialog-shadow: var(--shadow-lg); --dialog-border: 1px solid var(--border); --dialog-width: min(var(--breakpoint-md), 100% - var(--gutters) * 2); /* Reveal transitions/animations */ --dialog-opacity--start: 0; --dialog-opacity--end: 1; --dialog-scale--start: 0.98; --dialog-scale--end: 1; --dialog-translate--start: 0, 0, 0; --dialog-translate--end: 0, 0, 0; --dialog-transition-delay--start: 0ms; --dialog-transition-delay--end: 150ms; }}/* Sizing tokens — second variables block (overrides --dialog-width above). */@layer variables { :root { --dialog-width: min(50ch, 100% - var(--gap-md) * 2); --dialog-height: fit-content; --dialog-background: var(--card); --dialog-foreground: var(--card-foreground); --dialog-radius: var(--radius-lg); }}@layer reset { /* =========================================================================== DIALOG — native <dialog> open/close animation, sizing, backdrop fade - In the reset layer so the .dialog component styling below wins. =========================================================================== */ /* Prevent body scroll when a dialog inside the preview is open */ /* Dialog animations with spring easing */ :where(dialog) { margin: auto; max-inline-size: calc(100% - var(--gap-md)); max-block-size: calc(100% - var(--gap-md)); border: var(--dialog-border); contain: layout style; opacity: var(--dialog-opacity--start); box-shadow: var(--dialog-shadow); overscroll-behavior: contain; overflow: auto; transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); transition: opacity var(--dialog-transition-duration) var(--dialog-transition-timing-function), transform var(--dialog-transition-duration) var(--dialog-transition-timing-function), padding var(--dialog-transition-duration) var(--dialog-transition-timing-function), block-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), inline-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), overlay var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete, display var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete; transition-delay: var(--dialog-transition-delay--start); } :where(dialog[open]) { transform: translate3d(var(--dialog-translate--end)) scale(var(--dialog-scale--end)); opacity: var(--dialog-opacity--end); transition-delay: var(--dialog-transition-delay--end); @starting-style { transition-delay: var(--dialog-transition-delay--start); transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); opacity: var(--dialog-opacity--start); } } /* Dialog backdrop with smooth fade transition */ :where(dialog)::backdrop { position: fixed; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; opacity: 0; overscroll-behavior: contain; overflow: auto; background-color: var(--dialog-backdrop-color); backdrop-filter: var(--dialog-backdrop-blur); transition: opacity var(--dialog-backdrop-transition-duration) var(--dialog-backdrop-transition-timing-function); } :where(dialog[open])::backdrop { opacity: 1; @starting-style { opacity: 0; } }}@layer zazz.components { .dialog { /* Overrides reset-layer --dialog-shadow (reset > variables) */ --dialog-shadow: var(--shadow-md); inline-size: var(--dialog-width); block-size: var(--dialog-height); background-color: var(--dialog-background); color: var(--dialog-foreground); box-shadow: var(--dialog-shadow); border-radius: var(--dialog-radius); anchor-name: --dialog-root; container-type: inline-size; container-name: dialog; font-size: var(--font-size-md); isolation: isolate; } .dialog[open] { grid-template-rows: minmax(0, 1fr); min-block-size: 0; } .dialog__close { position: absolute; top: var(--gap-xs); right: var(--gap-xs); z-index: 50; } .dialog__close > svg { inline-size: var(--step-4); block-size: var(--step-4); pointer-events: none; justify-content: center; align-items: center; display: flex; padding: 0; } .dialog__content { display: grid; align-self: center; grid-template-rows: auto minmax(0, 1fr) auto; position: relative; min-block-size: 0; overflow: clip; } .dialog__header { display: flex; flex-direction: column; padding-inline: var(--gap-sm); padding-block-start: var(--gap-sm); } /* Sticky top edge */ .dialog__header::after { content: ""; display: block; position: absolute; top: 100%; inline-size: 100%; block-size: var(--gap-md); background: linear-gradient(to top, transparent, var(--dialog-background)); } .dialog__body { display: grid; padding-inline: var(--gap-sm); padding-block: var(--gap-md); min-block-size: 0; min-block-size: var(--gap-xl); overflow-x: clip; overflow-y: auto; scrollbar-gutter: stable both-edges; } .dialog__footer { block-size: fit-content; position: sticky; bottom: 0; display: flex; justify-content: flex-end; align-self: end; flex-shrink: 0; gap: var(--gap-xs); padding: var(--gap-sm); border-top: 1px solid var(--border); background-color: var(--dialog-background); } .dialog[data-size="article"] { --dialog-width: var(--article-md); } .dialog[data-size="container"] { --dialog-width: var(--breakpoint-md); } .dialog[data-size="screen"] { --dialog-width: 100vi; --dialog-height: 100svh; --dialog-radius: 0; --dialog-shadow: none; max-inline-size: 100vi; max-block-size: 100svh; }}Alert
Loading components…
<button class="button" type="button" data-variant="destructive" command="show-modal" commandfor="alert-dialog-example-1"> Delete account</button><dialog id="alert-dialog-example-1" class="dialog" closedby="none"> <div class="dialog__content"> <header class="dialog__header flex-row items-center gap-xs text-destructive"> <svg class="size-md" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"> <rect width="256" height="256" fill="none" /> <path fill="currentColor" d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM120,104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm8,88a12,12,0,1,1,12-12A12,12,0,0,1,128,192Z" /> </svg> <h2 class="text-lg font-heading font-strong">Are you absolutely sure?</h2> </header> <div class="dialog__body italic"> <p> Alert dialogs must be closed by clicking the Cancel or Continue buttons. Changing <code>closedby="none"</code> to <code>closedby="any"</code> allows the user to close the dialog by clicking outside the dialog or pressing the Escape key. </p> </div> </div> <footer class="dialog__footer"> <button class="button" type="button" commandfor="alert-dialog-example-1" command="close"> Cancel </button> <button class="button" data-variant="destructive" type="button" commandfor="alert-dialog-example-1" command="close" > Delete account </button> </footer></dialog>/** * _dialog.css — Dialog (.dialog on native <dialog>) * * @layer variables, reset, components * @requires layers.css, _variables.css * @uses <dialog>, ::backdrop — native modal + backdrop * @uses @starting-style + allow-discrete — open/close opacity, transform, overlay * @uses anchor-name, container-type — layout hooks for sized variants * @tokens --dialog-* (@layer variables; sizing tokens in a second variables block) */@layer variables { :root { --dialog-display: grid; --dialog-backdrop-color: var(--shade-900); --dialog-transition-duration: var(--default-transition-duration); --dialog-transition-timing-function: var(--default-transition-timing-function); --dialog-backdrop-transition-duration: calc(var(--dialog-transition-duration) - 100ms); --dialog-backdrop-transition-timing-function: ease; --dialog-backdrop-blur: blur(5px); --dialog-shadow: var(--shadow-lg); --dialog-border: 1px solid var(--border); --dialog-width: min(var(--breakpoint-md), 100% - var(--gutters) * 2); /* Reveal transitions/animations */ --dialog-opacity--start: 0; --dialog-opacity--end: 1; --dialog-scale--start: 0.98; --dialog-scale--end: 1; --dialog-translate--start: 0, 0, 0; --dialog-translate--end: 0, 0, 0; --dialog-transition-delay--start: 0ms; --dialog-transition-delay--end: 150ms; }}/* Sizing tokens — second variables block (overrides --dialog-width above). */@layer variables { :root { --dialog-width: min(50ch, 100% - var(--gap-md) * 2); --dialog-height: fit-content; --dialog-background: var(--card); --dialog-foreground: var(--card-foreground); --dialog-radius: var(--radius-lg); }}@layer reset { /* =========================================================================== DIALOG — native <dialog> open/close animation, sizing, backdrop fade - In the reset layer so the .dialog component styling below wins. =========================================================================== */ /* Prevent body scroll when a dialog inside the preview is open */ /* Dialog animations with spring easing */ :where(dialog) { margin: auto; max-inline-size: calc(100% - var(--gap-md)); max-block-size: calc(100% - var(--gap-md)); border: var(--dialog-border); contain: layout style; opacity: var(--dialog-opacity--start); box-shadow: var(--dialog-shadow); overscroll-behavior: contain; overflow: auto; transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); transition: opacity var(--dialog-transition-duration) var(--dialog-transition-timing-function), transform var(--dialog-transition-duration) var(--dialog-transition-timing-function), padding var(--dialog-transition-duration) var(--dialog-transition-timing-function), block-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), inline-size var(--dialog-transition-duration) var(--dialog-transition-timing-function), overlay var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete, display var(--dialog-transition-duration) var(--dialog-transition-timing-function) allow-discrete; transition-delay: var(--dialog-transition-delay--start); } :where(dialog[open]) { transform: translate3d(var(--dialog-translate--end)) scale(var(--dialog-scale--end)); opacity: var(--dialog-opacity--end); transition-delay: var(--dialog-transition-delay--end); @starting-style { transition-delay: var(--dialog-transition-delay--start); transform: translate3d(var(--dialog-translate--start)) scale(var(--dialog-scale--start)); opacity: var(--dialog-opacity--start); } } /* Dialog backdrop with smooth fade transition */ :where(dialog)::backdrop { position: fixed; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; opacity: 0; overscroll-behavior: contain; overflow: auto; background-color: var(--dialog-backdrop-color); backdrop-filter: var(--dialog-backdrop-blur); transition: opacity var(--dialog-backdrop-transition-duration) var(--dialog-backdrop-transition-timing-function); } :where(dialog[open])::backdrop { opacity: 1; @starting-style { opacity: 0; } }}@layer zazz.components { .dialog { /* Overrides reset-layer --dialog-shadow (reset > variables) */ --dialog-shadow: var(--shadow-md); inline-size: var(--dialog-width); block-size: var(--dialog-height); background-color: var(--dialog-background); color: var(--dialog-foreground); box-shadow: var(--dialog-shadow); border-radius: var(--dialog-radius); anchor-name: --dialog-root; container-type: inline-size; container-name: dialog; font-size: var(--font-size-md); isolation: isolate; } .dialog[open] { grid-template-rows: minmax(0, 1fr); min-block-size: 0; } .dialog__close { position: absolute; top: var(--gap-xs); right: var(--gap-xs); z-index: 50; } .dialog__close > svg { inline-size: var(--step-4); block-size: var(--step-4); pointer-events: none; justify-content: center; align-items: center; display: flex; padding: 0; } .dialog__content { display: grid; align-self: center; grid-template-rows: auto minmax(0, 1fr) auto; position: relative; min-block-size: 0; overflow: clip; } .dialog__header { display: flex; flex-direction: column; padding-inline: var(--gap-sm); padding-block-start: var(--gap-sm); } /* Sticky top edge */ .dialog__header::after { content: ""; display: block; position: absolute; top: 100%; inline-size: 100%; block-size: var(--gap-md); background: linear-gradient(to top, transparent, var(--dialog-background)); } .dialog__body { display: grid; padding-inline: var(--gap-sm); padding-block: var(--gap-md); min-block-size: 0; min-block-size: var(--gap-xl); overflow-x: clip; overflow-y: auto; scrollbar-gutter: stable both-edges; } .dialog__footer { block-size: fit-content; position: sticky; bottom: 0; display: flex; justify-content: flex-end; align-self: end; flex-shrink: 0; gap: var(--gap-xs); padding: var(--gap-sm); border-top: 1px solid var(--border); background-color: var(--dialog-background); } .dialog[data-size="article"] { --dialog-width: var(--article-md); } .dialog[data-size="container"] { --dialog-width: var(--breakpoint-md); } .dialog[data-size="screen"] { --dialog-width: 100vi; --dialog-height: 100svh; --dialog-radius: 0; --dialog-shadow: none; max-inline-size: 100vi; max-block-size: 100svh; }}API
| Attribute | Where | Values |
|---|---|---|
command | trigger | show-modal, close |
commandfor | trigger | id of the <dialog> |
data-size | .dialog | article, container, screen |
closedby | <dialog> | any, closerequest, none |