Dialog
A window overlaid on either the primary window or another dialog window.
Examples
Without close button
Set closeButton={false} on DialogHeader to hide the default close button.
Nested dialog
Dialogs can be nested inside each other. Use data-nested-dialog-open and
--nested-dialogs to visually de-emphasize parent dialogs while a child dialog is open.
Row footer
Use direction="row" on DialogFooter to align buttons horizontally.
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 "@/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} />
);
function DialogClose({ className, ...props }: BaseDialog.Close.Props) {
return (
<BaseDialog.Close
data-slot="dialog-close"
className={cn("in-data-nested-dialog-open:hidden", className)}
{...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 z-50 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 z-50 flex w-96 max-w-[calc(100vw-3rem)] -translate-x-1/2 -translate-y-[calc(50%+2rem*var(--nested-dialogs))] flex-col overflow-hidden rounded-3xl bg-dialog text-dialog-foreground shadow-xs ring ring-border",
"transition-all duration-200 ease-[cubic-bezier(.22,1,.36,1)] will-change-transform",
"scale-[calc(1-0.1*var(--nested-dialogs))] opacity-[calc(1-min(var(--nested-dialogs),1))]",
"data-starting-style:translate-y-[calc(-50%+1.5rem)] data-starting-style:scale-90 data-starting-style:opacity-0",
"data-ending-style:translate-y-[calc(-50%+1.5rem)] data-ending-style:scale-90 data-ending-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.