Dialog provides structured primitives for modal workflows such as confirms,
forms, and focused task flows.
Use DialogTrigger to open, DialogContent for the modal surface, and
DialogHeader / DialogFooter for layout scaffolding.
Preview
Usage
import { Button } from '@branditdev/ui';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from './dialog';
export function DialogDemo() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant='outline'>Open dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Publish package</DialogTitle>
<DialogDescription>
Review release notes and confirm before publishing.
</DialogDescription>
</DialogHeader>
<DialogFooter showCloseButton>
<Button>Publish now</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
API
Dialog(
props):Element
Defined in: components/dialog/dialog.tsx:45
Accessible modal dialog root powered by Radix primitives.
Parameters
| Name | Type | Optional | Default | Description |
|---|---|---|---|---|
| props | DialogProps | no | - | Dialog root props. |
Returns
Element
A dialog root wrapper.
Source
'use client';
import { XIcon } from 'lucide-react';
import { Dialog as DialogPrimitive } from 'radix-ui';
import * as React from 'react';
import { cn, Button } from '@branditdev/ui';
export type DialogProps = React.ComponentProps<typeof DialogPrimitive.Root>;
export type DialogTriggerProps = React.ComponentProps<
typeof DialogPrimitive.Trigger
>;
export type DialogPortalProps = React.ComponentProps<
typeof DialogPrimitive.Portal
>;
export type DialogCloseProps = React.ComponentProps<
typeof DialogPrimitive.Close
>;
export type DialogOverlayProps = React.ComponentProps<
typeof DialogPrimitive.Overlay
>;
export type DialogContentProps = React.ComponentProps<
typeof DialogPrimitive.Content
> & {
showCloseButton?: boolean;
};
export type DialogHeaderProps = React.ComponentProps<'div'>;
export type DialogFooterProps = React.ComponentProps<'div'> & {
showCloseButton?: boolean;
};
export type DialogTitleProps = React.ComponentProps<
typeof DialogPrimitive.Title
>;
export type DialogDescriptionProps = React.ComponentProps<
typeof DialogPrimitive.Description
>;
function Dialog({ ...props }: DialogProps) {
return <DialogPrimitive.Root data-slot='dialog' {...props} />;
}
function DialogTrigger({ ...props }: DialogTriggerProps) {
return <DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />;
}
function DialogPortal({ ...props }: DialogPortalProps) {
return <DialogPrimitive.Portal data-slot='dialog-portal' {...props} />;
}
function DialogClose({ ...props }: DialogCloseProps) {
return <DialogPrimitive.Close data-slot='dialog-close' {...props} />;
}
function DialogOverlay({ className, ...props }: DialogOverlayProps) {
return (
<DialogPrimitive.Overlay
data-slot='dialog-overlay'
className={cn(
'data-[state=open]:backdrop-blur-xs data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
className
)}
{...props}
/>
);
}
function DialogContent({
className,
children,
showCloseButton = true,
...props
}: DialogContentProps) {
return (
<DialogPortal data-slot='dialog-portal'>
<DialogOverlay />
<DialogPrimitive.Content
data-slot='dialog-content'
className={cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg',
className
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close
data-slot='dialog-close'
className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<XIcon />
<span className='sr-only'>Close</span>
</DialogPrimitive.Close>
)}
</DialogPrimitive.Content>
</DialogPortal>
);
}
function DialogHeader({ className, ...props }: DialogHeaderProps) {
return (
<div
data-slot='dialog-header'
className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
{...props}
/>
);
}
function DialogFooter({
className,
showCloseButton = false,
children,
...props
}: DialogFooterProps) {
return (
<div
data-slot='dialog-footer'
className={cn(
'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
className
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close asChild>
<Button variant='outline'>Close</Button>
</DialogPrimitive.Close>
)}
</div>
);
}
function DialogTitle({ className, ...props }: DialogTitleProps) {
return (
<DialogPrimitive.Title
data-slot='dialog-title'
className={cn('text-lg leading-none font-semibold', className)}
{...props}
/>
);
}
function DialogDescription({ className, ...props }: DialogDescriptionProps) {
return (
<DialogPrimitive.Description
data-slot='dialog-description'
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
);
}
export {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
};