import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@registry/components/ui/dialog";
import { Button } from "@registry/components/ui/button";
export function DialogExample() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline">Open Dialog</Button>} />
<DialogContent>
<DialogHeader>
<DialogTitle>Confirm Action</DialogTitle>
<DialogDescription>
Are you sure you want to proceed? This action cannot be undone.
</DialogDescription>
</DialogHeader>
<DialogBody>
<p className="text-sm text-gray-600 dark:text-gray-400">
Additional context or details about the action can go here.
</p>
</DialogBody>
<DialogFooter>
<DialogClose render={<Button variant="secondary">Cancel</Button>} />
<Button>Continue</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
} Examples
Without close button
Set closeButton={false} on DialogHeader to hide the default close button.
import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@registry/components/ui/dialog";
import { Button } from "@registry/components/ui/button";
export function DialogNoCloseButtonExample() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline">No Close Button</Button>} />
<DialogContent>
<DialogHeader closeButton={false}>
<DialogTitle>Notice</DialogTitle>
<DialogDescription>
This dialog has no close button in the header. Use the action below to dismiss it.
</DialogDescription>
</DialogHeader>
<DialogBody>
<p className="text-sm text-gray-600 dark:text-gray-400">
You must explicitly choose an action to close this dialog.
</p>
</DialogBody>
<DialogFooter>
<DialogClose render={<Button>Got it</Button>} />
</DialogFooter>
</DialogContent>
</Dialog>
);
} Row footer
Use direction="row" on DialogFooter to align buttons horizontally.
import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@registry/components/ui/dialog";
import { Button } from "@registry/components/ui/button";
export function DialogRowFooterExample() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline">Row Footer</Button>} />
<DialogContent>
<DialogHeader>
<DialogTitle>Save Changes</DialogTitle>
<DialogDescription>Your changes will be saved to the cloud.</DialogDescription>
</DialogHeader>
<DialogBody>
<p className="text-sm text-gray-600 dark:text-gray-400">
Review your changes before confirming.
</p>
</DialogBody>
<DialogFooter direction="row">
<DialogClose render={<Button variant="secondary">Cancel</Button>} />
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
} Installation
Copy the source code below into your project:
import { mergeProps, useRender } from "@base-ui/react";
import { Dialog as BaseDialog } from "@base-ui/react/dialog";
import { cn } from "@registry/lib/utils";
import { XIcon } from "@phosphor-icons/react";
import { Button } from "./button";
const Dialog = (props: BaseDialog.Root.Props) => <BaseDialog.Root data-slot="dialog" {...props} />;
const DialogPortal = (props: BaseDialog.Portal.Props) => (
<BaseDialog.Portal data-slot="dialog-portal" {...props} />
);
const DialogClose = (props: BaseDialog.Close.Props) => (
<BaseDialog.Close data-slot="dialog-close" {...props} />
);
function DialogTrigger(props: BaseDialog.Trigger.Props) {
return <BaseDialog.Trigger data-slot="dialog-trigger" {...props} />;
}
const createDialogHandle = BaseDialog.createHandle;
function DialogBackdrop({ className, ...props }: BaseDialog.Backdrop.Props) {
return (
<BaseDialog.Backdrop
className={cn(
"fixed inset-0 bg-black/30 backdrop-blur-md transition-all duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0",
className,
)}
data-slot="dialog-backdrop"
{...props}
/>
);
}
function DialogTitle(props: BaseDialog.Title.Props) {
return <BaseDialog.Title className="text-lg font-bold" data-slot="dialog-title" {...props} />;
}
function DialogDescription({ className, ...props }: BaseDialog.Description.Props) {
return (
<BaseDialog.Description
className={cn("text-sm text-muted-foreground", className)}
data-slot="dialog-description"
{...props}
/>
);
}
function DialogContent({
className,
children,
dialogPortalProps,
dialogBackdropProps,
...props
}: BaseDialog.Popup.Props & {
dialogPortalProps?: BaseDialog.Portal.Props;
dialogBackdropProps?: BaseDialog.Backdrop.Props;
}) {
return (
<BaseDialog.Portal {...dialogPortalProps}>
<DialogBackdrop {...dialogBackdropProps} />
<BaseDialog.Popup
className={cn(
"fixed top-1/2 left-1/2 -mt-8 flex w-96 max-w-[calc(100vw-3rem)] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-3xl bg-dialog text-dialog-foreground shadow-xs transition-all duration-150 data-ending-style:scale-90 data-ending-style:opacity-0 data-starting-style:scale-90 data-starting-style:opacity-0",
className,
)}
data-slot="dialog-popup"
{...props}
>
{children}
</BaseDialog.Popup>
</BaseDialog.Portal>
);
}
function DialogHeader({
className,
children,
closeButton = true,
}: {
className?: string;
closeButton?: boolean;
children?: React.ReactNode;
}) {
return (
<div className={cn("relative flex flex-col p-6", className)} data-slot="dialog-header">
{closeButton && (
<DialogClose
className="absolute top-4 right-4"
render={<Button className="size-5" size="icon" variant="secondary" />}
>
<XIcon className="size-3" />
</DialogClose>
)}
{children}
</div>
);
}
function DialogBody({ className, ...props }: useRender.ComponentProps<"div">) {
const dialogBodyElement = useRender({
defaultTagName: "div",
props: {
...mergeProps<"div">(props, {
className: cn("flex flex-col gap-3 px-6 pb-6", className),
}),
"data-slot": "dialog-body",
},
});
return dialogBodyElement;
}
function DialogFooter({
children,
direction = "column",
className,
}: {
children: React.ReactNode;
direction?: "row" | "column";
className?: string;
}) {
return (
<div
className={cn(
"flex gap-2 border-t border-border bg-muted p-6",
direction === "row" && "flex-row justify-end",
direction === "column" && "flex-col",
className,
)}
data-slot="dialog-footer"
>
{children}
</div>
);
}
export {
Dialog,
DialogBackdrop,
DialogTrigger,
DialogPortal,
DialogTitle,
DialogDescription,
DialogClose,
DialogContent,
DialogFooter,
DialogBody,
DialogHeader,
createDialogHandle,
}; API Reference
Dialog
This component does not add any props on top of Base UI Dialog.Root . See the Base UI docs for the full API reference.
DialogTrigger
This component does not add any props on top of Base UI Dialog.Trigger . See the Base UI docs for the full API reference.
DialogContent
The DialogContent component extends the Base UI Dialog.Popup
props and adds the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| dialogPortalProps | BaseDialog.Portal.Props | — | Props forwarded to the underlying Portal component. |
| dialogBackdropProps | BaseDialog.Backdrop.Props | — | Props forwarded to the underlying Backdrop component. |
DialogHeader
| Prop | Type | Default | Description |
|---|---|---|---|
| closeButton | boolean | true | Whether to show the default close button in the header. |
| className | string | — | Additional CSS classes to apply to the header container. |
DialogBody
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Additional CSS classes to apply to the body container. |
DialogFooter
| Prop | Type | Default | Description |
|---|---|---|---|
| direction | "row" | "column" | "column" | Layout direction for the footer actions. |
| className | string | — | Additional CSS classes to apply to the footer container. |
DialogTitle
This component does not add any props on top of Base UI Dialog.Title . See the Base UI docs for the full API reference.
DialogDescription
The DialogDescription component extends the Base UI Dialog.Description
props and adds the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Additional CSS classes to apply to the description element. |
DialogBackdrop
The DialogBackdrop component extends the Base UI Dialog.Backdrop
props and adds the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Additional CSS classes to apply to the backdrop element. |
DialogClose
This component does not add any props on top of Base UI Dialog.Close . See the Base UI docs for the full API reference.
DialogPortal
This component does not add any props on top of Base UI Dialog.Portal . See the Base UI docs for the full API reference.