Dialog
Centered modal overlay for alerts and forms.
Selectors
.dialog- Centered modal overlay with glass background and backdrop. Add to
<dialog>element. .dialog-close- Positioned close button (top-right corner).
data-modal- Prevents closing via backdrop click (requires
js/cider.js).
Default
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Close Document</button>
<dialog class="dialog">
<header>
<h2>Save changes to "Untitled"?</h2>
<p>Your changes will be lost if you don't save them.</p>
</header>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Don't Save</button>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-gray">Cancel</button>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-filled">Save</button>
</footer>
</dialog>
Destructive
<button onclick="openDialog(this.nextElementSibling)" class="btn-filled btn-destructive">Delete Project</button>
<dialog class="dialog">
<header>
<h2>Delete project?</h2>
<p>This will permanently delete the project "My Portfolio" and all of its files. This action is irreversible.</p>
</header>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Cancel</button>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-filled btn-destructive">Delete Project</button>
</footer>
</dialog>
With Icon
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Sign Out</button>
<dialog class="dialog">
<header>
<div class="mx-auto mb-4 flex size-12 items-center justify-center rounded-full bg-secondary">
<svg class="size-6 text-tertiary-foreground" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/></svg>
</div>
<h2 class="text-center">Sign out of your account?</h2>
<p class="text-center">You will need to enter your credentials again to sign back in.</p>
</header>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Cancel</button>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-filled btn-destructive">Sign Out</button>
</footer>
</dialog>
Form Dialog
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Edit Profile</button>
<dialog class="dialog">
<header>
<h2>Edit Profile</h2>
<p>Make changes to your profile here.</p>
</header>
<section>
<div class="space-y-4">
<label class="space-y-2">Name
<input type="text" value="John Doe" />
</label>
<label class="space-y-2">Email
<input type="email" value="john@example.com" />
</label>
</div>
</section>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Cancel</button>
<button class="btn-filled" onclick="closeDialog(this.closest('dialog'))">Save Changes</button>
</footer>
</dialog>
Scrollable Content
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Scrollable Dialog</button>
<dialog class="dialog">
<header>
<h2>Terms of Service</h2>
<p>Please read the following terms carefully.</p>
</header>
<section>
<div class="space-y-4 text-sm text-tertiary-foreground">
<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.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.</p>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis.</p>
<p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias.</p>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae.</p>
</div>
</section>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Decline</button>
<button class="btn-filled" onclick="closeDialog(this.closest('dialog'))">Accept</button>
</footer>
</dialog>
With Close Button
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Share Link</button>
<dialog class="dialog">
<button aria-label="Close" onclick="closeDialog(this.closest('dialog'))" class="dialog-close">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
<header>
<h2>Share Link</h2>
<p>Anyone with the link will be able to view this document.</p>
</header>
<section>
<div class="flex gap-2">
<input type="text" value="https://example.com/doc/abc123" readonly class="flex-1" />
<button class="btn-gray" onclick="navigator.clipboard && navigator.clipboard.writeText('https://example.com/doc/abc123')">Copy</button>
</div>
</section>
</dialog>
Custom Content
<button onclick="openDialog(this.nextElementSibling)" class="btn-tinted">Invite Members</button>
<dialog class="dialog" style="max-width: 480px;">
<header>
<h2>Invite Team Members</h2>
<p>Add colleagues to collaborate on this project.</p>
</header>
<section>
<div class="space-y-4">
<div class="flex gap-2">
<input type="email" placeholder="email@example.com" class="flex-1" />
<button class="btn-gray">Invite</button>
</div>
<div class="space-y-2">
<div class="flex items-center justify-between rounded-lg border px-3 py-2">
<div class="flex items-center gap-2.5">
<div class="avatar size-8 text-xs bg-primary/10 text-primary">SC</div>
<div>
<p class="text-sm font-medium">Sarah Chen</p>
<p class="text-xs text-tertiary-foreground">sarah@example.com</p>
</div>
</div>
<span class="text-xs text-tertiary-foreground">Owner</span>
</div>
<div class="flex items-center justify-between rounded-lg border px-3 py-2">
<div class="flex items-center gap-2.5">
<div class="avatar size-8 text-xs bg-primary/10 text-primary">JD</div>
<div>
<p class="text-sm font-medium">John Doe</p>
<p class="text-xs text-tertiary-foreground">john@example.com</p>
</div>
</div>
<select class="h-auto w-auto py-1 pl-2 pr-8 text-xs rounded-lg" aria-label="User role">
<option>Viewer</option>
<option selected>Editor</option>
<option>Admin</option>
</select>
</div>
</div>
</div>
</section>
<footer>
<button onclick="closeDialog(this.closest('dialog'))" class="btn-tinted">Cancel</button>
<button class="btn-filled" onclick="closeDialog(this.closest('dialog'))">Done</button>
</footer>
</dialog>
Button Order
Place the primary action on the right, secondary in the middle, and cancel/dismiss on the left. Apple convention: the rightmost button is the default action.
Browser Support
Dialog uses corner-shape: squircle for Apple-style rounded corners. This requires Safari 18+ or Chrome 130+. Standard border-radius is applied as a fallback in older browsers.
Usage
Adds backdrop click to close with exit animation, focus trapping, scroll lock, and focus restoration. The native <dialog> element handles open/close — this script is optional.
API
openDialog(dialogElement)- Opens the dialog as a modal. Guards against re-opening an already-open or closing dialog.
closeDialog(dialogElement)- Closes the dialog with an exit animation, restoring focus and scroll position.
Both functions are available as globals and via CiderUI.dialog.open() / CiderUI.dialog.close().
Accessibility
- Uses native
<dialog>for built-in modal semantics. - Auto-sets
aria-labelledbyfrom the dialog's heading andaria-describedbyfrom its description. - Focus is trapped inside the dialog while open; first focusable element receives focus on open.
- Escape closes the dialog. Backdrop click also dismisses (unless
data-modalis set). - Focus is restored to the triggering element on close.