Documentation Index
Fetch the complete documentation index at: https://mintlify.com/shadcn-ui/ui/llms.txt
Use this file to discover all available pages before exploring further.
Installation
npm install @base-ui/react
Or use the CLI:
npx shadcn@latest add dialog
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
Component API
The root dialog component built on Radix UI.
Props:
open - Control dialog open state
onOpenChange - Callback when open state changes
defaultOpen - Initial open state
modal - Whether dialog is modal (default: true)
DialogTrigger
The element that opens the dialog.
Props:
asChild - Compose with child element
DialogContent
The dialog content container.
Props:
showCloseButton - Show close button (default: true)
onEscapeKeyDown - Callback when escape is pressed
onPointerDownOutside - Callback when clicking outside
Container for title and description.
DialogTitle
The dialog title (required for accessibility).
DialogDescription
The dialog description.
Container for dialog actions.
Props:
showCloseButton - Show close button (default: false)
DialogClose
Closes the dialog.
Examples
Custom Close Button
Replace the default close control with your own button:
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
export function CustomCloseButton() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent showCloseButton={false}>
<DialogHeader>
<DialogTitle>Custom Close Button</DialogTitle>
<DialogDescription>
This dialog uses a custom close button in the footer.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
No Close Button
Hide the close button completely:
<Dialog>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<DialogContent showCloseButton={false}>
<DialogHeader>
<DialogTitle>No Close Button</DialogTitle>
<DialogDescription>
This dialog has no close button.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
Scrollable Content
Long content can scroll while the header stays in view:
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
export function ScrollableDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<DialogContent className="max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Terms and Conditions</DialogTitle>
<DialogDescription>
Please read and accept our terms and conditions.
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
{Array.from({ length: 20 }).map((_, i) => (
<p key={i}>
This is example content paragraph {i + 1}. The dialog content
scrolls while the header and footer remain visible.
</p>
))}
</div>
</DialogContent>
</Dialog>
)
}
Keep actions visible while the content scrolls:
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
export function StickyFooterDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<DialogContent className="flex max-h-[80vh] flex-col">
<DialogHeader>
<DialogTitle>Long Form</DialogTitle>
<DialogDescription>
Fill out the form below to continue.
</DialogDescription>
</DialogHeader>
<div className="flex-1 overflow-y-auto">
{Array.from({ length: 20 }).map((_, i) => (
<div key={i} className="mb-4">
<label className="mb-2 block text-sm font-medium">
Field {i + 1}
</label>
<input
type="text"
className="w-full rounded border px-3 py-2"
/>
</div>
))}
</div>
<DialogFooter className="sticky bottom-0 bg-background pt-4">
<Button variant="outline">Cancel</Button>
<Button>Submit</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
Controlled Dialog
Control the dialog open state:
import * as React from "react"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
export function ControlledDialog() {
const [open, setOpen] = React.useState(false)
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Controlled Dialog</DialogTitle>
<DialogDescription>
This dialog's open state is controlled.
</DialogDescription>
</DialogHeader>
<Button onClick={() => setOpen(false)}>Close from inside</Button>
</DialogContent>
</Dialog>
)
}
Form Dialog
Dialog containing a form:
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
export function FormDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Edit Profile</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="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" defaultValue="Pedro Duarte" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" defaultValue="@peduarte" className="col-span-3" />
</div>
</div>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
Accessibility
- Built on Radix UI for full accessibility
- Focus is trapped within the dialog
- Escape key closes the dialog
- Background content is inert
- Screen reader compatible
- ARIA labels and roles
API Reference
See the Base UI Dialog documentation for complete API details.