Skip to content

Dialog

Built on the native <dialog>: focus stays inside while it’s open, the page behind can’t be used or scrolled, Escape closes it and focus returns to the button that opened it. It always sits on top of the page — no z-index, and parents with overflow or transform can’t clip it.

Delete the project?

This removes the project and its files. It can't be undone.
---
import { Button, Dialog } from 'bws-astro-ui';
---
<Dialog title="Delete the project?" text="This removes the project and its files." width="sm">
<Button slot="activator" color="error" variant="tonal">Delete…</Button>
<Fragment slot="actions">
<Button variant="text" data-dialog-close>Cancel</Button>
<Button color="error" data-dialog-close>Delete</Button>
</Fragment>
</Dialog>

The content works like a Card: title, text and an actions slot, or anything in the default slot. A long body scrolls while the title and actions stay in place.

To… Use
open from a button next to it the activator slot
open from anywhere data-dialog-open="dialog-id" on any element
close from inside data-dialog-close on any element in the dialog, or closable for a × button
close a specific dialog data-dialog-close="dialog-id"
open on page load the open prop
open or close in a script the native dialog.showModal() / dialog.close()

A click on the backdrop and Escape close the dialog too.

Terms of service

1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

2. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

3. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

4. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

5. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

6. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

7. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

8. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

9. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

10. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.

<Button data-dialog-open="terms">Read the terms</Button>
<Dialog id="terms" title="Terms of service" width="lg" closable>
<p>…</p>
<Button slot="actions" data-dialog-close>Close</Button>
</Dialog>

The native close event fires on the dialog when it closes:

document.getElementById('terms').addEventListener('close', () => {
// …
});

With persistent, the backdrop and Escape don’t close the dialog — it gives a small bounce instead, and only your buttons (or the × of closable) close it.

Accept the terms

Only the button closes this dialog.

A Form with method="dialog" closes the dialog when it’s submitted — and only once every field is valid:

Contact us

<Dialog title="Contact us" closable width="sm">
<Button slot="activator">Contact</Button>
<Form method="dialog">
<TextInput name="name" label="Name" rules={[required()]} />
<Button type="submit">Send</Button>
</Form>
</Dialog>

width takes a step — xs 20rem, sm 24rem, default 32rem, lg 42rem, xl 56rem — or pixels, and never gets wider than the screen. fullscreen fills the whole screen, which suits phones.

Fullscreen

Takes the whole screen.

While a dialog is open, the page behind it doesn’t scroll. If the page has a classic scrollbar, its space is kept (scrollbar-gutter), so the content doesn’t shift sideways when the scrollbar disappears. This also applies to dialogs opened with dialog.showModal() from your own code.

Prop Type Default
title string —
text string — body text —
width xs · sm · default · lg · xl · number (px) default
fullscreen boolean false
persistent boolean — backdrop and Escape don’t close it false
closable boolean — a × button in the corner false
closeLabel string — accessible name of the × button Close
open boolean — open on page load false
titleTag h2 · h3 · h4 · div h2
id string — for data-dialog-open; generated when missing —
class string —

Any other attribute goes to the <dialog>.

Slot Content
activator the element that opens the dialog
title replaces title
default the body — replaces text
actions buttons at the bottom
Created byBanach Web SolutionsBanach Web Solutions