Components
Dialog
A modal or non-modal dialog component built on the native <dialog> element with trigger integration, light dismiss, and event hooks.
Preview
Delete your account?
This action cannot be undone. All your data will be permanently deleted.
Usage
<button type="button" data-dialog-trigger="confirm-delete">
Delete account
</button>
<st-dialog id="confirm-delete">
<h2 class="text-lg font-semibold">Delete your account?</h2>
<p class="mt-2 text-sm text-muted-foreground">
This action cannot be undone.
</p>
<form method="dialog" class="mt-4 flex justify-end gap-2">
<button type="submit" value="cancel">Cancel</button>
<button type="submit" value="confirm">Delete</button>
</form>
</st-dialog>
Triggers
Any element with data-dialog-trigger="<dialog-id>" opens the dialog when clicked. Multiple triggers can target the same dialog.
By default, dialogs open as modals. To open non-modal, add data-dialog-modal="false" to the trigger.
<!-- Opens as modal (default) -->
<button data-dialog-trigger="my-dialog">Open Modal</button>
<!-- Opens as non-modal -->
<button data-dialog-trigger="my-dialog" data-dialog-modal="false">
Open Non-Modal
</button>
Form Integration
Use <form method="dialog"> to handle Cancel / Confirm patterns. The submitter button's value is exposed as the dialog's return value:
const dialog = document.getElementById('confirm-delete')
dialog.addEventListener('st-dialog:close', (e) => {
if (e.detail.returnValue === 'confirm') {
// perform action
}
})
Programmatic API
const dialog = document.getElementById('my-dialog')
dialog.open() // Open as modal
dialog.openNonModal() // Open as non-modal
dialog.close() // Close without return value
dialog.close('confirmed') // Close with return value
dialog.isOpen // Check open state
Light Dismiss
By default, clicking outside the dialog (on the backdrop) closes it. To disable for critical dialogs:
<st-dialog id="critical" data-st-dialog-no-light-dismiss>
<!-- User must explicitly cancel or confirm -->
</st-dialog>
Events
All events bubble.
| Event | Detail |
|---|---|
| st-dialog:open | { modal: boolean } |
| st-dialog:close | { returnValue: string } |
Styling
Default styling matches the shadcn popover aesthetic. Override on the inner <dialog> element:
st-dialog dialog {
max-width: 28rem;
padding: 2rem;
}
For full control, write your <dialog> explicitly inside:
<st-dialog id="custom">
<dialog class="my-custom-dialog">
<!-- your styling, your structure -->
</dialog>
</st-dialog>