Dialog

An impactful dialog that ensures your important messages and actions get the attention they deserve! 💬✨



Instalation

1. Install dependencies:

npm install @radix-ui/react-dialog @radix-ui/react-visually-hidden tailwindcss-animate

2. Configure your tailwind.config.ts add:

{
  content: [...],
  theme: [...],
 
  // add plugin
  plugins: [require("tailwindcss-animate")],
}


3. Copy the code 👇 into your project:

"use client";
 
import * as ReactDialog from "@radix-ui/react-dialog";
import { cn } from "@/lib/utils";
import { cva, VariantProps } from "class-variance-authority";
import React, { HTMLAttributes, ReactNode } from "react";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { X } from "lucide-react";
 
const Dialog = ReactDialog.Root;
const DialogTrigger = ReactDialog.Trigger;
 
const overlayVariants = cva(
  ` fixed bg-black/80 font-head
    data-[state=open]:fade-in-0
    data-[state=open]:animate-in 
    data-[state=closed]:animate-out 
    data-[state=closed]:fade-out-0 
  `,
  {
    variants: {
      variant: {
        default: "inset-0 z-50 bg-black/80",
        none: "fixed bg-transparent",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);
 
interface IDialogBackgroupProps
  extends HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof overlayVariants> {}
 
const DialogBackdrop = React.forwardRef<HTMLDivElement, IDialogBackgroupProps>(
  (inputProps: IDialogBackgroupProps, forwardedRef) => {
    const { variant = "default", className, ...props } = inputProps;
 
    return (
      <ReactDialog.Overlay
        className={cn(overlayVariants({ variant }), className)}
        {...props}
      />
    );
  }
);
 
const dialogVariants = cva(
  `fixed z-50 left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 
  flex flex-col border-2 border-black shadow-md gap-4 overflow-y-auto bg-white
  w-full h-fit max-h-[80vh] max-w-[97%] duration-300
  data-[state=open]:animate-in 
  data-[state=open]:slide-in-from-left-1/2 
  data-[state=open]:slide-in-from-top-[48%]
  data-[state=open]:fade-in-0 
  data-[state=open]:zoom-in-95 
  data-[state=closed]:animate-out 
  data-[state=closed]:fade-out-0 
  data-[state=closed]:slide-out-to-top-[48%] 
  data-[state=closed]:slide-out-to-left-1/2 
  data-[state=closed]:zoom-out-95`,
  {
    variants: {
      size: {
        auto: "max-w-fit",
        sm: "lg:max-w-[30%]",
        md: "lg:max-w-[40%]",
        lg: "lg:max-w-[50%]",
        xl: "lg:max-w-[60%]",
        "2xl": "lg:max-w-[70%]",
        "3xl": "lg:max-w-[80%]",
        "4xl": "lg:max-w-[90%]",
        screen: "max-w-[100%]",
      },
    },
    defaultVariants: {
      size: "auto",
    },
  }
);
 
interface IDialogContentProps
  extends HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof dialogVariants> {
  overlay?: IDialogBackgroupProps;
}
 
const DialogContent = React.forwardRef<HTMLDivElement, IDialogContentProps>(
  (inputProps: IDialogContentProps, forwardedRef) => {
    const {
      children,
      size = "auto",
      className,
      overlay,
      ...props
    } = inputProps;
 
    return (
      <ReactDialog.Portal>
        <DialogBackdrop {...overlay} />
        <ReactDialog.Content
          className={cn(dialogVariants({ size }), className)}
          ref={forwardedRef}
          {...props}
        >
          <VisuallyHidden>
            <ReactDialog.Title />
          </VisuallyHidden>
          <div className="flex flex-col relative">{children}</div>
        </ReactDialog.Content>
      </ReactDialog.Portal>
    );
  }
);
 
interface IDialogDescriptionProps extends HTMLAttributes<HTMLDivElement> {}
const DialogDescription = ({
  children,
  className,
  ...props
}: IDialogDescriptionProps) => {
  return (
    <ReactDialog.Description className={cn(className)} {...props}>
      {children}
    </ReactDialog.Description>
  );
};
 
const dialogFooterVariants = cva(
  "flex items-center justify-end border-t-2 border-black min-h-12 gap-4 px-4 py-2",
  {
    variants: {
      variant: {
        default: "bg-white text-black",
      },
      position: {
        fixed: "sticky bottom-0",
        static: "static",
      },
    },
    defaultVariants: {
      position: "fixed",
    },
  }
);
 
export interface IDialogFooterProps
  extends HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof dialogFooterVariants> {}
 
const DialogFooter = ({
  children,
  className,
  position,
  variant,
  ...props
}: IDialogFooterProps) => {
  return (
    <div
      className={cn(dialogFooterVariants({ position, variant }), className)}
      {...props}
    >
      {children}
    </div>
  );
};
 
const dialogHeaderVariants = cva(
  "flex items-center justify-between border-b-2 border-black px-4 min-h-12",
  {
    variants: {
      variant: {
        default: "bg-primary-400 text-black",
      },
      position: {
        fixed: "sticky top-0",
        static: "static",
      },
    },
    defaultVariants: {
      variant: "default",
      position: "static",
    },
  }
);
 
const DialogHeaderDefaultLayout = ({ children }: { children: ReactNode }) => {
  return (
    <>
      {children}
      <DialogTrigger title="Close pop-up" className="cursor-pointer" asChild>
        <X />
      </DialogTrigger>
    </>
  );
};
 
interface IDialogHeaderProps
  extends HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof dialogHeaderVariants>,
    ReactDialog.DialogTitleProps {}
 
const DialogHeader = ({
  children,
  className,
  position,
  variant,
  asChild,
  ...props
}: IDialogHeaderProps) => {
  return (
    <div
      className={cn(dialogHeaderVariants({ position, variant }), className)}
      {...props}
    >
      {asChild ? (
        children
      ) : (
        <DialogHeaderDefaultLayout>{children}</DialogHeaderDefaultLayout>
      )}
    </div>
  );
};
 
const DialogComponent = Object.assign(Dialog, {
  Trigger: DialogTrigger,
  Header: DialogHeader,
  Content: DialogContent,
  Description: DialogDescription,
  Footer: DialogFooter,
});
 
export { DialogComponent as Dialog };


Example

Confirm dialog message





Dialog size variants



Dialog with form



Notes

For customize anything on dialog you can change className for the component and doas you want.

Last Updated: 04 Nov, 2024