Dialog
Dialog renders content in an overlay that blocks interaction with the rest of the page. Built on Radix UI's dialog primitive with focus trapping and scroll locking.
Interactive example#
Dialog · Live example
Open the dialog, tab through its fields, and press Escape to return focus.
The code uses shared demo presentation helpers. Their complete source and styling are included in the LLM build context.
Import#
TSX
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
DialogClose,
} from '@clidey/ux';
Basic dialog#
TSX
<Dialog>
<DialogTrigger>
<Button variant="outline">Open dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-1">
<Label htmlFor="name">Name</Label>
<Input id="name" defaultValue="Jane Doe" />
</div>
<div className="space-y-1">
<Label htmlFor="username">Username</Label>
<Input id="username" defaultValue="@janedoe" />
</div>
</div>
<DialogFooter>
<DialogClose>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
Controlled dialog#
TSX
import { useState } from 'react';
function ControlledDialog() {
const [open, setOpen] = useState(false);
async function handleSave() {
await saveData();
setOpen(false);
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger>
<Button>Open</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirm action</DialogTitle>
<DialogDescription>
This will apply changes to all selected items.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
<Button onClick={handleSave}>Confirm</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
Without close button#
Pass showCloseButton={false} to hide the default X button in the corner:
TSX
<DialogContent showCloseButton={false}>
<DialogHeader>
<DialogTitle>Processing...</DialogTitle>
</DialogHeader>
<div className="flex justify-center py-4">
<Spinner size="lg" />
</div>
</DialogContent>
Large content dialog#
TSX
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Terms of Service</DialogTitle>
</DialogHeader>
<ScrollArea className="h-64">
<div className="space-y-4 text-sm">
{/* long content */}
</div>
</ScrollArea>
<DialogFooter>
<DialogClose>
<Button variant="outline">Decline</Button>
</DialogClose>
<Button>Accept</Button>
</DialogFooter>
</DialogContent>
Sub-components#
| Component | Description |
|---|---|
Dialog | Root component. Manages open state. |
DialogTrigger | Button or element that opens the dialog. Renders as its child automatically for ux components (Button, Badge, ...) and intrinsic elements, so no asChild is needed; pass asChild only for other ref-forwarding elements. See Triggers and asChild. |
DialogPortal | Renders dialog outside the DOM tree. Used internally. |
DialogOverlay | Semi-transparent backdrop using the --backdrop CSS token. Used internally. |
DialogContent | The dialog panel itself. Contains all visible content. |
DialogHeader | Top section with consistent spacing for title/description. |
DialogTitle | Accessible dialog title (required for a11y). |
DialogDescription | Supporting text below the title. |
DialogFooter | Bottom section, flex row right-aligned for action buttons. |
DialogClose | Button that closes the dialog. Use asChild to render as any element. |
DialogContent Props
| Prop | Type | Default | Description |
|---|---|---|---|
showCloseButton | boolean | true | Shows or hides the default close (X) button in the top-right corner. |
className | string | — | Additional CSS classes. Use to change max-width. |
onOpenAutoFocus | (e: Event) => void | — | Override default focus behavior on open. |
Was this page helpful?
