Dialog

A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.

Installation

Install the following dependencies:

npm install @radix-ui/react-dialog

Copy and paste the following code into your project.

'use client';
 
import * as DialogPrimitive from '@radix-ui/react-dialog';
import clsx from 'clsx';
import { X } from 'lucide-react';
import { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, forwardRef } from 'react';
import styles from './styles.module.scss';
 
const Dialog = DialogPrimitive.Root;
 
const DialogTrigger = DialogPrimitive.Trigger;
 
const DialogPortal = DialogPrimitive.Portal;
 
const DialogClose = DialogPrimitive.Close;
 
const DialogOverlay = forwardRef<
    ElementRef<typeof DialogPrimitive.Overlay>,
    ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
    <DialogPrimitive.Overlay ref={ref} className={clsx(styles.dialog__overlay, className)} {...props} />
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
 
const DialogContent = forwardRef<
    ElementRef<typeof DialogPrimitive.Content>,
    ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
    <DialogPortal>
        <DialogOverlay />
        <DialogPrimitive.Content ref={ref} className={clsx(styles.dialog__content, className)} {...props}>
            {children}
            <DialogPrimitive.Close className={styles.dialog__content__close}>
                <X className={styles.dialog__content__close__icon} />
                <span className={styles.sr_only}>Close</span>
            </DialogPrimitive.Close>
        </DialogPrimitive.Content>
    </DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
 
const DialogHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
    <div className={clsx(styles.dialog__header, className)} {...props} />
);
DialogHeader.displayName = 'DialogHeader';
 
const DialogFooter = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
    <div className={clsx(styles.dialog__footer, className)} {...props} />
);
DialogFooter.displayName = 'DialogFooter';
 
const DialogTitle = forwardRef<
    ElementRef<typeof DialogPrimitive.Title>,
    ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
    <DialogPrimitive.Title ref={ref} className={clsx(styles.dialog__title, className)} {...props} />
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
 
const DialogDescription = forwardRef<
    ElementRef<typeof DialogPrimitive.Description>,
    ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
    <DialogPrimitive.Description ref={ref} className={clsx(styles.dialog__description, className)} {...props} />
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;
 
export {
    Dialog,
    DialogClose,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogOverlay,
    DialogPortal,
    DialogTitle,
    DialogTrigger,
};

Update the import paths to match your project setup.

Usage

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>

Examples

Custom close button

Notes

To activate the Dialog component from within a Context Menu or Dropdown Menu, you must encase the Context Menu or Dropdown Menu component in the Dialog component. For more information, refer to the linked issue here.

<Dialog>
    <ContextMenu>
        <ContextMenuTrigger>Right click</ContextMenuTrigger>
        <ContextMenuContent>
            <ContextMenuItem>Open</ContextMenuItem>
            <ContextMenuItem>Download</ContextMenuItem>
            <DialogTrigger asChild>
                <ContextMenuItem>
                    <span>Delete</span>
                </ContextMenuItem>
            </DialogTrigger>
        </ContextMenuContent>
    </ContextMenu>
    <DialogContent>
        <DialogHeader>
            <DialogTitle>Are you absolutely sure?</DialogTitle>
            <DialogDescription>
                This action cannot be undone. Are you sure you want to permanently delete this file from our servers?
            </DialogDescription>
        </DialogHeader>
        <DialogFooter>
            <Button type='submit'>Confirm</Button>
        </DialogFooter>
    </DialogContent>
</Dialog>