Examples
Default
Confirm action
Are you sure you want to proceed? This action affects all selected items.
Danger
Delete project
This will permanently delete the project and all of its files. This action cannot be undone.
Sizes
Small
24rem max-width.
Large
48rem max-width for content-heavy modals.
Basic usage
<brio-dialog dismissible>
<dialog class="dialog" id="demo-basic">
<header>
<h3>Publish draft</h3>
<button
class="dismiss"
type="button"
commandfor="demo-basic"
command="close"
aria-label="Close"
>
×
</button>
</header>
<section>
<p>
Your draft is ready to go live. Publishing makes it visible to all
subscribers; you can always edit afterward.
</p>
</section>
<footer>
<button
class="button is-outlined"
type="button"
commandfor="demo-basic"
command="close"
>
Cancel
</button>
<button
class="button"
type="button"
commandfor="demo-basic"
command="close"
>
Publish
</button>
</footer>
</dialog>
</brio-dialog>
<button class="button" type="button" commandfor="demo-basic" command="show-modal">
Open dialog
</button>
</div>
</div>
Size
<div>
<brio-dialog dismissible>
<dialog class="dialog is-sm" id="demo-sm">
<header>
<h3>Delete this item?</h3>
</header>
<section>
<p>This can't be undone.</p>
</section>
<footer>
<button
class="button is-outlined"
type="button"
commandfor="demo-sm"
command="close"
>
Cancel
</button>
<button
class="button is-danger"
type="button"
commandfor="demo-sm"
command="close"
>
Delete
</button>
</footer>
</dialog>
</brio-dialog>
<brio-dialog dismissible>
<dialog class="dialog is-lg" id="demo-lg">
<header>
<h3>Edit project</h3>
<button
class="dismiss"
type="button"
commandfor="demo-lg"
command="close"
aria-label="Close"
>
×
</button>
</header>
<section>
<p>
Wider surface for forms with multiple fields or side-by-side
layouts. At this size the body still grows to its content; reach for
<code>.is-full</code> when the content is tall enough to need
internal scroll.
</p>
</section>
<footer>
<button
class="button is-outlined"
type="button"
commandfor="demo-lg"
command="close"
>
Cancel
</button>
<button
class="button"
type="button"
commandfor="demo-lg"
command="close"
>
Save
</button>
</footer>
</dialog>
</brio-dialog>
<brio-dialog dismissible>
<dialog class="dialog is-full" id="demo-full">
<header>
<h3>Terms of service</h3>
<button
class="dismiss"
type="button"
commandfor="demo-full"
command="close"
aria-label="Close"
>
×
</button>
</header>
<section>
<p>
Fills the viewport with padding and gives the body its own internal
scroll. Useful for long-form content (terms, release notes,
changelogs) or content-heavy dialogs on mobile.
</p>
<p>
Scroll me: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.
</p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur.
</p>
</section>
<footer>
<button
class="button"
type="button"
commandfor="demo-full"
command="close"
>
Close
</button>
</footer>
</dialog>
</brio-dialog>
<div class="cluster is-tight">
<button
class="button is-outlined"
type="button"
commandfor="demo-sm"
command="show-modal"
>
Open .is-sm
</button>
<button
class="button is-outlined"
type="button"
commandfor="demo-lg"
command="show-modal"
>
Open .is-lg
</button>
<button
class="button is-outlined"
type="button"
commandfor="demo-full"
command="show-modal"
>
Open .is-full
</button>
</div>
</div>
</div>
</div>
Color
<div>
<brio-dialog dismissible>
<dialog class="dialog is-danger" id="demo-danger">
<header>
<h3>Delete workspace?</h3>
</header>
<section>
<p>
This will permanently delete the workspace, its content, and all
member access. The action can't be undone.
</p>
<p>Type the workspace name to confirm before proceeding.</p>
</section>
<footer>
<button
class="button is-danger is-outlined"
type="button"
commandfor="demo-danger"
command="close"
>
Cancel
</button>
<button
class="button is-danger"
type="button"
commandfor="demo-danger"
command="close"
>
Delete
</button>
</footer>
</dialog>
</brio-dialog>
<button
class="button is-danger"
type="button"
commandfor="demo-danger"
command="show-modal"
>
Open destructive dialog
</button>
</div>
</div>
</div>
State and interaction
<div>
<brio-dialog>
<dialog class="dialog is-danger" id="demo-nondismissible">
<header>
<h3>Confirm before continuing</h3>
</header>
<section>
<p>
This dialog is non-dismissible: Escape and backdrop clicks don't
close it. The reader must press a button to proceed. Use sparingly
-- only for actions where an accidental dismiss would cause harm.
</p>
</section>
<footer>
<button
class="button is-danger is-outlined"
type="button"
commandfor="demo-nondismissible"
command="close"
>
Cancel
</button>
<button
class="button is-danger"
type="button"
commandfor="demo-nondismissible"
command="close"
>
Proceed
</button>
</footer>
</dialog>
</brio-dialog>
<button
class="button is-danger is-outlined"
type="button"
commandfor="demo-nondismissible"
command="show-modal"
>
Open non-dismissible
</button>
</div>
</div>
</div>
Reading the user's choice
<brio-dialog dismissible>
<dialog class="dialog is-sm is-danger" id="demo-return">
<form method="dialog">
<header>
<h3>Delete this item?</h3>
</header>
<section>
<p>This can't be undone.</p>
</section>
<footer>
<button class="button is-danger is-outlined" value="cancel">
Cancel
</button>
<button class="button is-danger" value="delete">Delete</button>
</footer>
</form>
</dialog>
</brio-dialog>
<div class="cluster is-tight">
<button
class="button is-danger"
type="button"
commandfor="demo-return"
command="show-modal"
>
Open
</button>
<p id="demo-return-result" class="text-muted" aria-live="polite"></p>
</div>
<script>
(() => {
const dlg = document.getElementById('demo-return');
const out = document.getElementById('demo-return-result');
dlg.addEventListener('close', () => {
const v = dlg.returnValue;
out.textContent =
v === 'delete'
? 'Result: delete'
: v === 'cancel'
? 'Result: cancel'
: 'Result: dismissed (returnValue empty)';
});
})();
</script>
</div>
</div>
Awaiting the result from JavaScript
<brio-dialog dismissible>
<dialog class="dialog is-sm" id="demo-await">
<form method="dialog">
<header>
<h3>Save changes?</h3>
</header>
<section>
<p>Your draft has unsaved changes.</p>
</section>
<footer>
<button class="button is-outlined" value="discard">Discard</button>
<button class="button" value="save">Save</button>
</footer>
</form>
</dialog>
</brio-dialog>
<div class="cluster is-tight">
<button class="button" type="button" id="demo-await-trigger">Open</button>
<p id="demo-await-result" class="text-muted" aria-live="polite"></p>
</div>
<script>
(() => {
const trigger = document.getElementById('demo-await-trigger');
const out = document.getElementById('demo-await-result');
trigger.addEventListener('click', async () => {
const result = await brio.dialog.open('demo-await');
out.textContent =
result === 'save'
? 'Result: save'
: result === 'discard'
? 'Result: discard'
: 'Result: dismissed (returnValue empty)';
});
})();
</script>
</div>
</div>
Source comments
Dialog -- styled native <dialog> element
Structure -- semantic HTML carries the regions, no slot classes:
<brio-dialog dismissible>
<dialog class="dialog" id="my-dialog">
<header> <-- title + dismiss row, bordered separator
<h2>Title</h2>
<button class="dismiss" commandfor="my-dialog"
command="close" type="button" aria-label="Close">×</button>
</header>
<section> <-- padded content middle; <article> also accepted
…
</section>
<footer> <-- right-aligned actions row, bordered separator
<button class="button is-outlined"
commandfor="my-dialog" command="close">Cancel</button>
<button class="button">Confirm</button>
</footer>
</dialog>
</brio-dialog>
<button commandfor="my-dialog" command="show-modal">Open</button>
The dialog has padding: 0 on the root; each slot owns its padding.
Header and footer carry separator borders that wrap the content
section above and below. Direct-child only -- a nested <header> or
<footer> in body content (e.g. an .alert with its own footer) does
NOT pick up dialog chrome.
Form-method-dialog wrapper: when a <form method="dialog"> wraps the
three slots (the native return-value pattern), the slots sit one
level deeper. The CSS matches both shapes:
<dialog class="dialog">
<form method="dialog">
<header>...</header>
<section>...</section>
<footer>...</footer>
</form>
</dialog>
Body element: <section> for generic dialog content (the canonical
fit -- "thematic grouping of content"), or <article> when the body
is a self-contained composition (a single notification, a single
news item displayed in a dialog).
Open: native via commandfor + command="show-modal"
Close: native via commandfor + command="close"
Escape: native cancel (blocked by <brio-dialog> when non-dismissible)
Backdrop: <brio-dialog dismissible> closes on backdrop click
Entry/exit animation uses @starting-style plus transition-behavior:
allow-discrete on overlay and display -- no JS class toggling needed.
Heading level (h2-h6) is author's choice per document hierarchy.
Dialog CSS normalizes the title visual via --dialog-title-font-size.
Reference
Source: src/css/dialog.css
Applies to
.dialog
Classes
| Class | Kind | Description |
|---|---|---|
.is-sm | variant | Narrow dialog at 24rem max width |
.is-lg | variant | Wide dialog at 48rem max width |
.is-full | variant | Near-viewport-width dialog with scrollable body |
.no-border | opt-out | Strips all borders from the dialog and its slots |
.is-danger | variant | Danger-tinted dialog for destructive actions |
Slots
| Slot | Description |
|---|---|
> header, > form[method="dialog"] > header | A header slot starts with a <header> element |
> :is(section, article), > form[method="dialog"] > :is(section, article) | Body slots start with <section> or <article> elements |
> footer, > form[method="dialog"] > footer | Footer slots start with a <footer> element |
Tokens
| Token | Default | Description |
|---|---|---|
--dialog-bg | var(--color-surface-float) | Background color for the dialog surface |
--dialog-color | var(--color-text) | Text color inside the dialog |
--dialog-max-width | 32rem | Maximum width of the dialog |
--dialog-padding-inline | var(--ui-pad-inline-relaxed) | Inline-axis padding for header, body, and footer slots |
--dialog-padding-block | var(--ui-pad-block-relaxed) | Block-axis padding for the body slot |
--dialog-radius | var(--radius-md) | Border radius for the dialog |
--dialog-border-color | var(--color-border) | Border color for the dialog frame |
--dialog-border-width | var(--border-width-default) | Border width for the dialog frame |
--dialog-header-border-color | var(--color-border) | Separator border color below the header |
--dialog-footer-border-color | var(--color-border) | Separator border color above the footer |
--dialog-title-font-size | var(--ui-font-size-base) | Font size for the dialog title heading |