Modals and dialogs
Production-grade SaaS UI skills for AI coding agents (React + Tailwind + shadcn/ui) — Codex, Claude Code, Cursor, OpenCode. One npx command to install.
npx -y skills add param087/saas-ui-skills --skill modals-and-dialogsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when building modals, sheets, drawers, or confirmation flows — choosing Dialog vs Sheet vs Drawer vs AlertDialog, focus trapping, destructive-action confirms, and forms inside overlays without losing data.
SKILL.md
3.7 KB, as published. Nobody here has run it
Modals & Dialogs
Overview
Overlays interrupt — use them sparingly and correctly. shadcn/ui (on Radix) gives you four primitives with built-in focus trap, Esc to close, scroll lock, and aria-modal. Your job is choosing the right one and handling the edge cases: destructive confirms, forms with unsaved input, and not stacking overlays.
When to use
- A focused task or confirmation needs to block the page.
- Building a side panel for details/filters/quick-edit.
- A
<div>overlay is being hand-rolled (you'll miss focus trap + keyboard).
Pick the right primitive
| Use | Primitive | When |
|---|---|---|
| Centered modal | Dialog | Short forms, focused tasks |
| Side panel | Sheet | Details, filters, edit alongside context |
| Bottom drawer | Drawer (vaul) | Mobile-friendly, touch dismiss |
| Confirm/destruct | AlertDialog | Yes/no decisions; no dismiss-on-outside-click |
Destructive confirmation
AlertDialog (not Dialog) for irreversible actions — it requires an explicit choice and won't close on outside click or Esc accidentally losing the decision:
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete project</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete this project?</AlertDialogTitle>
<AlertDialogDescription>
This permanently deletes the project and all its data. This can’t be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
onClick={deleteProject}
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
For high-risk deletes, require typing the resource name to enable the button.
Forms inside dialogs
Control open so you can keep the dialog open on validation error and close only on success:
const [open, setOpen] = React.useState(false);
async function onSubmit(values) {
await save(values); // throws → dialog stays open, error shows
setOpen(false); // success → close
toast.success("Saved");
}
<Dialog open={open} onOpenChange={setOpen}>…</Dialog>
Warn before discarding unsaved changes: intercept onOpenChange and confirm if the form isDirty.
Accessibility (mostly handled, don't break it)
- Always include
DialogTitle(+DialogDescription) — they backaria-labelledby/describedby. Visually hide the title withsr-onlyif needed, but keep it. - Focus moves into the dialog on open and returns to the trigger on close — don't disable this.
- Don't stack modals. Replace content or use a multi-step flow instead.
Pitfalls
Dialogfor destructive actions — outside-click dismiss can skip the decision; useAlertDialog.- Closing on submit before the request resolves — close on success only.
- No unsaved-changes guard — users lose form input on accidental dismiss.
- Missing
DialogTitle— breaks the accessible name; Radix will warn. - Modal-on-modal stacking — confusing focus; redesign the flow.
- Putting huge content in a modal — use a
Sheetor a full page instead.
Hand-off
Overlays that host forms-and-validation, confirm data-tables row actions, and pair with notifications-and-toasts for post-action feedback.