Dialog
A modal window that interrupts the current flow to capture user attention. Blocks background interaction, traps keyboard focus, and dismisses on ESC or clicking the overlay. Built on @base-ui/react/dialog.
Anatomy
<Dialog> is the stateful root. DialogTrigger opens it, DialogContent renders in a portal with an overlay. DialogHeader and DialogFooter are layout helpers. DialogClose dismisses from anywhere inside the content. The showCloseButton prop on DialogContent controls the built-in X button (default: true).
DialogTrigger → portalDialogHeader + DialogFootershowCloseButton (default: true)
Examples
Form dialog
Confirmation
No close button
Close Button
showCloseButton on DialogContent toggles the built-in X button in the header area. Disable it when the footer already provides a clear dismiss path.
showCloseButton={true} (default)showCloseButton={false}Design Guidelines
Do
- Use for tasks needing a decision. Dialogs are best when the user must complete an action before returning — forms, confirmations, settings.
- Keep dialogs focused. One task per dialog. If the content sprawls, consider a Sheet or a dedicated page instead.
- Always provide a cancel path. Include a
DialogCloseor cancel button — never force the user to complete the action.
Don't
- Don't nest dialogs. Opening a dialog from inside a dialog breaks focus management and confuses users.
- Don't use for simple notifications. If no decision is needed, use a Toaster or inline Alert instead.
- Don't block critical workflows. Avoid wrapping common actions in dialogs — reserve them for genuinely interruptive tasks.
Developer Reference
Accessibility
role="dialog"witharia-labelledbyandaria-describedbywired toDialogTitleandDialogDescription.- Keyboard focus is trapped inside the open dialog — Tab cycles through focusable elements only.
- ESC key and clicking the backdrop both dismiss the dialog.
DialogClosecan wrap any element viaasChildto create custom dismiss triggers.- Content renders into a portal — it is visually above the page but remains in the accessible tree.
Usage
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
DialogClose,
} from "@/components/ui/dialog"
// Form dialog
<Dialog>
<DialogTrigger asChild>
<Button>Edit Profile</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Profile</DialogTitle>
<DialogDescription>Make changes and click save.</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
<Input placeholder="Name" />
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
// Without close button
<DialogContent showCloseButton={false}>...</DialogContent>
// Controlled
const [open, setOpen] = useState(false)
<Dialog open={open} onOpenChange={setOpen}>...</Dialog>