Dialog
Modal window for confirmations and focused tasks.
Installation
npm install @aspyn-io/kit @aspyn-io/tokensimport {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
DialogClose,
} from "@aspyn-io/kit";Destructive confirmation
The standard confirm pattern for irreversible actions.
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">Delete workspace</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete workspace?</DialogTitle>
<DialogDescription>
This permanently deletes the workspace and all of its data.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="ghost">Cancel</Button>
</DialogClose>
<Button variant="destructive">Delete</Button>
</DialogFooter>
</DialogContent>
</Dialog>Scrollable body
Long content? DialogBody pins the header and footer, scrolls the middle, and separates it with borders — no layout work required.
<DialogContent>
<DialogHeader>
<DialogTitle>Terms of service</DialogTitle>
<DialogDescription>Updated August 2026.</DialogDescription>
</DialogHeader>
<DialogBody>
{/* any amount of content — scrolls between pinned header/footer */}
</DialogBody>
<DialogFooter>
<Button>Accept</Button>
</DialogFooter>
</DialogContent>Form in a dialog
<Dialog>
<DialogTrigger asChild>
<Button>Rename project</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Rename project</DialogTitle>
</DialogHeader>
<div className="space-y-2">
<Label htmlFor="project-name">Project name</Label>
<Input id="project-name" defaultValue="aspyn-crm" />
</div>
<DialogFooter>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>Notes
- Focus is trapped inside the dialog and returned to the trigger on close (Radix).
- Escape and clicking the overlay close it; DialogTitle is required for accessible naming.
- For controlled dialogs (e.g. close after async save), use open + onOpenChange.