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.
---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.
Opening and closing
Section titled “Opening and closing”| 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.
<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', () => { // …});Persistent
Section titled “Persistent”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.
Forms in a dialog
Section titled “Forms in a dialog”A Form with method="dialog" closes the dialog when it’s submitted — and
only once every field is valid:
<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.
Page scroll
Section titled “Page scroll”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 |