Dialog
The dialog opens a modal window above the page and blocks interaction with everything behind it. Use it for confirmations, short forms, and alerts that need a decision; for a panel that slides in from the edge, reach for the sheet.
<button id="dialog-1-trigger" class="btn btn-outline">Open Dialog</button>
<dialog class="dialog" data-sp-toggle="#dialog-1-trigger">
<form class="dialog-panel">
<button
type="button"
class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
aria-label="Close"
data-sp-dismiss
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<div class="dialog-header">
<h2 class="dialog-title">Edit profile</h2>
<p class="dialog-description">
Make changes to your profile here. Click save when you're done.
</p>
</div>
<div class="dialog-content">
<div class="field-group">
<div class="field">
<label class="label" for="dialog-profile-name">Name</label>
<input
class="input"
id="dialog-profile-name"
name="name"
value="Pedro Duarte"
/>
</div>
<div class="field">
<label class="label" for="dialog-profile-username">Username</label>
<input
class="input"
id="dialog-profile-username"
name="username"
value="@peduarte"
/>
</div>
</div>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-outline" data-sp-dismiss>
Cancel
</button>
<button type="submit" class="btn">Save changes</button>
</div>
</form>
</dialog>Usage
Add the dialog class to a <dialog> element. Give your trigger an id, then point the dialog at it with data-sp-toggle. The trigger can be any element. Close the dialog with data-sp-dismiss on a button, a backdrop click, or the Escape key.
<!-- This is a button toggling the dialog -->
<button id="my-trigger" class="btn btn-outline">Open Dialog</button>
<!-- This is the dialog -->
<dialog class="dialog" data-sp-toggle="#my-trigger">
<div class="dialog-panel">
<div class="dialog-header">
<h2 class="dialog-title">Title</h2>
<p class="dialog-description">Description</p>
</div>
<div class="dialog-footer">
<button class="btn btn-outline" data-sp-dismiss>Close</button>
</div>
</div>
</dialog>Examples
Custom close button
Any element with data-sp-dismiss closes the dialog, so put close buttons wherever the layout needs them.
<button id="dialog-share-trigger" class="btn btn-outline">Share</button>
<dialog class="dialog" data-sp-toggle="#dialog-share-trigger">
<div class="dialog-panel">
<button
class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
aria-label="Close"
data-sp-dismiss
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<div class="dialog-header">
<h2 class="dialog-title">Share link</h2>
<p class="dialog-description">
Anyone who has this link will be able to view this.
</p>
</div>
<div class="dialog-content">
<div class="field">
<label class="label sr-only" for="dialog-share-link">Link</label>
<input
class="input"
id="dialog-share-link"
value="https://startingpointui.com/guides/installation"
readonly
/>
</div>
</div>
<div class="dialog-footer sm:justify-start">
<button class="btn" data-sp-dismiss>Close</button>
</div>
</div>
</dialog>Sticky footer
Cap the body's height and let it scroll on its own: the header and footer stay pinned while the content scrolls between them.
<button id="dialog-sticky-trigger" class="btn btn-outline">
Sticky Footer
</button>
<dialog class="dialog" data-sp-toggle="#dialog-sticky-trigger">
<div class="dialog-panel">
<button
class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
aria-label="Close"
data-sp-dismiss
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<div class="dialog-header">
<h2 class="dialog-title">Sticky Footer</h2>
<p class="dialog-description">
This dialog has a sticky footer that stays visible while the content
scrolls.
</p>
</div>
<div
class="dialog-content scrollbar-none max-h-[50vh] overflow-y-auto leading-normal"
>
<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. 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. 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. 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. 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. 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. 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>
</div>
<div class="dialog-footer">
<button class="btn btn-outline" data-sp-dismiss>Close</button>
</div>
</div>
</dialog>Scrollable content
The same scrolling body without a footer.
<button id="dialog-scroll-trigger" class="btn btn-outline">
Scrollable Content
</button>
<dialog class="dialog" data-sp-toggle="#dialog-scroll-trigger">
<div class="dialog-panel">
<button
class="btn btn-ghost btn-xs btn-icon absolute top-3 right-3"
aria-label="Close"
data-sp-dismiss
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<div class="dialog-header">
<h2 class="dialog-title">Scrollable Content</h2>
<p class="dialog-description">
This is a dialog with scrollable content.
</p>
</div>
<div
class="dialog-content scrollbar-none max-h-[50vh] overflow-y-auto leading-normal"
>
<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. 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. 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. 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. 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. 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. 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>
</div>
</div>
</dialog>Initially open
Add the shown class to the dialog and it renders open, with no enter animation. Useful when the server re-renders the page mid-flow, like a submitted form coming back with validation errors, so the dialog is still open exactly where the user left it.
<button id="dialog-open-trigger" class="btn btn-outline">Create account</button>
<dialog class="dialog shown" data-sp-toggle="#dialog-open-trigger">
<form class="dialog-panel">
<div class="dialog-header">
<h2 class="dialog-title">Create account</h2>
<p class="dialog-description">
Pick a username and enter your email to get started.
</p>
</div>
<div class="dialog-content">
<div class="field-group">
<div class="field">
<label class="label" for="dialog-open-username">Username</label>
<input
class="input"
id="dialog-open-username"
name="username"
value="pedro"
aria-invalid="true"
/>
<p class="field-error">This username is already taken.</p>
</div>
<div class="field">
<label class="label" for="dialog-open-email">Email</label>
<input
class="input"
id="dialog-open-email"
name="email"
type="email"
value="[email protected]"
/>
</div>
</div>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-outline" data-sp-dismiss>
Cancel
</button>
<button type="submit" class="btn">Create account</button>
</div>
</form>
</dialog>Alert dialog
An alert dialog interrupts the user and requires a choice. Add data-sp-static so a backdrop click won't dismiss it (Escape still closes, so keyboard users are never stuck) and author role="alertdialog" on the element. Put autofocus on the least destructive action and skip the close button.
<button id="alert-trigger" class="btn btn-outline">Show Dialog</button>
<dialog
class="dialog"
role="alertdialog"
data-sp-toggle="#alert-trigger"
data-sp-static
>
<div class="dialog-panel">
<div class="dialog-header">
<h2 class="dialog-title">Are you absolutely sure?</h2>
<p class="dialog-description">
This will permanently delete your account and remove your data from our
servers.
</p>
</div>
<div class="dialog-footer">
<button class="btn btn-outline" data-sp-dismiss autofocus>Cancel</button>
<button class="btn" data-sp-dismiss>Continue</button>
</div>
</div>
</dialog>RTL
Add dir="rtl" to any parent element, typically <html>, to render right-to-left. Position the close button with inset-e-3 instead of right-3 so it follows the text direction. See the RTL guide for details.
<div id="dialog-rtl-demo" dir="rtl">
<button id="dialog-rtl-trigger" class="btn btn-outline" data-i18n="open">فتح الحوار</button>
<dialog class="dialog" data-sp-toggle="#dialog-rtl-trigger">
<form class="dialog-panel">
<button type="button" class="btn btn-ghost btn-xs btn-icon absolute top-3 inset-e-3" aria-label="Close" data-sp-dismiss>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
<div class="dialog-header">
<h2 class="dialog-title" data-i18n="editProfile">تعديل الملف الشخصي</h2>
<p class="dialog-description" data-i18n="description">قم بإجراء تغييرات على ملفك الشخصي هنا. انقر فوق حفظ عند الانتهاء.</p>
</div>
<div class="dialog-content">
<div class="field-group">
<div class="field">
<label class="label" for="dialog-rtl-name" data-i18n="name">الاسم</label>
<input class="input" id="dialog-rtl-name" name="name" value="Pedro Duarte" />
</div>
<div class="field">
<label class="label" for="dialog-rtl-username" data-i18n="username">اسم المستخدم</label>
<input class="input" id="dialog-rtl-username" name="username" value="@peduarte" />
</div>
</div>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-outline" data-sp-dismiss data-i18n="cancel">إلغاء</button>
<button type="submit" class="btn" data-i18n="save">حفظ التغييرات</button>
</div>
</form>
</dialog>
</div>
<script>
const translations = {
ar: { dir: "rtl", open: "فتح الحوار", editProfile: "تعديل الملف الشخصي", description: "قم بإجراء تغييرات على ملفك الشخصي هنا. انقر فوق حفظ عند الانتهاء.", name: "الاسم", username: "اسم المستخدم", cancel: "إلغاء", save: "حفظ التغييرات" },
he: { dir: "rtl", open: "פתח דיאלוג", editProfile: "ערוך פרופיל", description: "בצע שינויים בפרופיל שלך כאן. לחץ על שמור כשתסיים.", name: "שם", username: "שם משתמש", cancel: "בטל", save: "שמור שינויים" },
en: { dir: "ltr", open: "Open Dialog", editProfile: "Edit profile", description: "Make changes to your profile here. Click save when you're done.", name: "Name", username: "Username", cancel: "Cancel", save: "Save changes" },
};
window.addEventListener("message", (e) => {
const t = translations[e.data?.lang];
if (e.data?.type !== "sp-language" || !t) return;
document.getElementById("dialog-rtl-demo").dir = t.dir;
document.querySelectorAll("[data-i18n]").forEach((el) => {
el.textContent = t[el.dataset.i18n];
});
});
</script>CSS variables
The panel's spacing rhythm is one component-local variable: the panel derives its vertical padding and section gap from it, and each section its horizontal padding. Override it per instance with an arbitrary property, or for the whole app with a plain CSS rule.
<div class="dialog-panel [--dialog-spacing:--spacing(4)]"></div>Options
Dialog
Set each option with its own data-sp-* attribute on the dialog element.
<dialog class="dialog" data-sp-toggle="#my-trigger" data-sp-static></dialog>JavaScript
Events
Lifecycle events fire on the dialog element; before* events are cancelable.
el.addEventListener("sp-beforeshow", (e) => {
if (!ready) e.preventDefault(); // veto the open
});Methods
Get the instance with sp.dialog(el), then call its methods:
const dialog = sp.dialog(document.querySelector("#my-dialog"));
dialog.show();