Dialog
A hand-drawn Base UI dialog styled with shadcn conventions. It renders in a portal, traps focus, and closes on outside click or Escape.
Dialog
Every hand-drawn dialog composition.
Basic
With footer actions
Destructive confirm
Without close button
Installation
npx shadcn@latest add https://sketchcn.chuwii.com/r/dialog.jsonUsage
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export function DeleteDialog() {
return (
<Dialog>
<DialogTrigger render={<Button variant="destructive">Delete</Button>} />
<DialogContent>
<DialogHeader>
<DialogTitle>Delete this sketch?</DialogTitle>
<DialogDescription>This cannot be undone.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose render={<Button variant="ghost">Cancel</Button>} />
<Button variant="destructive">Delete</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Parts
| Part | Description |
|---|---|
Dialog | Root that owns the open state. |
DialogTrigger | Opens the dialog. |
DialogContent | The centred, outlined popup. |
DialogHeader | Title and description block. |
DialogTitle | Accessible name of the dialog. |
DialogDescription | Accessible description. |
DialogFooter | Action row, stacked on small screens. |
DialogClose | Closes the dialog. |
DialogOverlay | The backdrop, rendered for you by DialogContent. |
DialogPortal | The portal, also rendered for you. |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
showCloseButton | boolean | true | On DialogContent. Hides the corner close button when false. |
All other props are forwarded to the matching Base UI Dialog parts.
Examples
Form in a dialog
import { Button } from "@/components/ui/button";
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
export function NewSketchDialog() {
return (
<Dialog>
<DialogTrigger render={<Button>New sketch</Button>} />
<DialogContent>
<DialogHeader>
<DialogTitle>New sketch</DialogTitle>
<DialogDescription>Give it a name before you start.</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-3">
<Input placeholder="Sketch name" />
<Textarea placeholder="What is it for?" />
</div>
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
<Button>Create</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}Controlled open state
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
export function UnsavedChangesDialog() {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>
Leave page
</Button>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Leave without saving?</DialogTitle>
<DialogDescription>Your sketch has unsaved changes.</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>
Keep editing
</Button>
<Button variant="destructive" onClick={() => setOpen(false)}>
Discard
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}