Kosorikōsori alpha

Alert Dialog

A modal dialog that interrupts the user with important content and expects a response.

Installation

Install the primitive

Install the @radix-ui/react-alert-dialog package.

npm install @radix-ui/react-alert-dialog

Copy-paste the component

Copy and paste the component code in a .tsx file.

'use client';
 
import type { AlertDialogPortalProps } from '@radix-ui/react-alert-dialog';
import { forwardRef } from 'react';
import {
  Action,
  Cancel,
  Content,
  Description,
  Overlay,
  Portal,
  Root,
  Title,
  Trigger,
} from '@radix-ui/react-alert-dialog';
import { clsx } from 'clsx/lite';
import { tv } from 'tailwind-variants';
 
import type { ButtonProps } from '@kosori/ui/button';
import { buttonStyles } from '@kosori/ui/button';
 
const alertDialogStyles = tv({
  slots: {
    overlay: clsx(
      'fixed inset-0 z-50 bg-black-a6 backdrop-blur-sm',
      'data-[state=open]:animate-in data-[state=open]:fade-in-0',
      'data-[state=closed]:animate-out data-[state=closed]:fade-out-0',
    ),
    content: clsx(
      'fixed inset-1/2 z-50 grid h-fit w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border border-grey-line bg-grey-base p-6 shadow-md duration-200',
      'sm:rounded-lg',
      'md:w-full',
      'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
      'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]',
    ),
    header: clsx('flex flex-col space-y-2', 'first-letter:sm:text-left'),
    title: 'text-lg font-semibold',
    description: 'text-sm text-grey-text',
    footer: clsx(
      'flex flex-col-reverse',
      'sm:flex-row sm:justify-end sm:space-x-2',
    ),
  },
});
 
const { overlay, content, header, title, description, footer } =
  alertDialogStyles();
 
/**
 * AlertDialog component that displays a modal dialog for user confirmation or alerts.
 *
 * @param {React.ComponentPropsWithoutRef<typeof Root>} props - Additional props to pass to the alert dialog.
 *
 * @example
 * <AlertDialog>
 *   <AlertDialogTrigger>Open Alert</AlertDialogTrigger>
 *   <AlertDialogContent>
 *     <AlertDialogHeader>
 *       <AlertDialogTitle>Confirm Action</AlertDialogTitle>
 *       <AlertDialogDescription>
 *         Are you sure you want to proceed with this action?
 *       </AlertDialogDescription>
 *     </AlertDialogHeader>
 *     <AlertDialogFooter>
 *       <AlertDialogCancel>Cancel</AlertDialogCancel>
 *       <AlertDialogAction>Confirm</AlertDialogAction>
 *     </AlertDialogFooter>
 *   </AlertDialogContent>
 * </AlertDialog>
 *
 * @see {@link https://dub.sh/ui-alert-dialog Alert Dialog Docs} for further information.
 */
export const AlertDialog = Root;
 
/**
 * AlertDialogTrigger component for the AlertDialog that activates the dialog when clicked.
 *
 * @param {React.ComponentPropsWithoutRef<typeof Trigger>} props - Additional props to pass to the alert dialog trigger.
 *
 * @example
 * <AlertDialogTrigger>Open Alert</AlertDialogTrigger>
 */
export const AlertDialogTrigger = Trigger;
 
/**
 * AlertDialogPortal component for rendering the AlertDialog in a separate part of the DOM.
 *
 * @param {AlertDialogPortalProps} props - Additional props to pass to the alert dialog portal.
 *
 * @example
 * <AlertDialogPortal>
 *   <AlertDialogOverlay />
 *   <AlertDialogContent>...</AlertDialogContent>
 * </AlertDialogPortal>
 */
export const AlertDialogPortal = ({
  children,
  ...props
}: AlertDialogPortalProps) => <Portal {...props}>{children}</Portal>;
 
AlertDialogPortal.displayName = Portal.displayName;
 
type AlertDialogOverlayRef = React.ElementRef<typeof Overlay>;
type AlertDialogOverlayProps = React.ComponentPropsWithoutRef<typeof Overlay>;
 
/**
 * AlertDialogOverlay component that covers the background when the AlertDialog is open.
 *
 * @param {AlertDialogOverlayProps} props - Additional props to pass to the alert dialog overlay.
 *
 * @example
 * <AlertDialogOverlay />
 */
export const AlertDialogOverlay = forwardRef<
  AlertDialogOverlayRef,
  AlertDialogOverlayProps
>(({ className, ...props }, ref) => (
  <Overlay ref={ref} className={overlay({ className })} {...props} />
));
 
AlertDialogOverlay.displayName = Overlay.displayName;
 
type AlertDialogContentRef = React.ElementRef<typeof Content>;
type AlertDialogContentProps = React.ComponentPropsWithoutRef<typeof Content>;
 
/**
 * AlertDialogContent component for the AlertDialog that contains the main dialog content.
 *
 * @param {AlertDialogContentProps} props - Additional props to pass to the alert dialog content.
 *
 * @example
 * <AlertDialogContent>
 *   <AlertDialogTitle>Confirm Action</AlertDialogTitle>
 *   <AlertDialogDescription>
 *     Are you sure you want to proceed with this action?
 *   </AlertDialogDescription>
 * </AlertDialogContent>
 */
export const AlertDialogContent = forwardRef<
  AlertDialogContentRef,
  AlertDialogContentProps
>(({ className, ...props }, ref) => (
  <AlertDialogPortal>
    <AlertDialogOverlay />
    <Content ref={ref} className={content({ className })} {...props} />
  </AlertDialogPortal>
));
 
AlertDialogContent.displayName = Content.displayName;
 
type AlertDialogCancelRef = React.ElementRef<typeof Cancel>;
type AlertDialogRadixCancelProps = React.ComponentPropsWithoutRef<
  typeof Cancel
>;
type AlertDialogCancelProps = object &
  AlertDialogRadixCancelProps &
  ButtonProps;
 
/**
 * AlertDialogCancel button component for the AlertDialog that closes the dialog without taking action.
 *
 * @param {AlertDialogCancelProps} props - Additional props to pass to the cancel button.
 *
 * @example
 * <AlertDialogCancel>Cancel</AlertDialogCancel>
 */
export const AlertDialogCancel = forwardRef<
  AlertDialogCancelRef,
  AlertDialogCancelProps
>(({ variant = 'outline', intent, size, icon, className, ...props }, ref) => (
  <Cancel
    ref={ref}
    className={buttonStyles({
      variant,
      intent,
      size,
      icon,
      className,
    })}
    {...props}
  />
));
 
AlertDialogCancel.displayName = Cancel.displayName;
 
type AlertDialogActionRef = React.ElementRef<typeof Action>;
type AlertDialogRadixActionProps = React.ComponentPropsWithoutRef<
  typeof Action
>;
type AlertDialogActionProps = object &
  AlertDialogRadixActionProps &
  ButtonProps;
 
/**
 * AlertDialogAction button component for the AlertDialog that confirms the action.
 *
 * @param {AlertDialogActionProps} props - Additional props to pass to the action button.
 *
 * @example
 * <AlertDialogAction>Confirm</AlertDialogAction>
 */
export const AlertDialogAction = forwardRef<
  AlertDialogActionRef,
  AlertDialogActionProps
>(({ variant, intent, size, icon, className, ...props }, ref) => (
  <Action
    ref={ref}
    className={buttonStyles({
      variant,
      intent,
      size,
      icon,
      className,
    })}
    {...props}
  />
));
 
AlertDialogAction.displayName = Action.displayName;
 
type AlertDialogHeaderProps = React.HTMLAttributes<HTMLDivElement>;
 
/**
 * AlertDialogHeader component for the AlertDialog that contains the title and description.
 *
 * @param {AlertDialogHeaderProps} props - Additional props to pass to the alert dialog header.
 *
 * @example
 * <AlertDialogHeader>
 *   <AlertDialogTitle>Confirm Action</AlertDialogTitle>
 *   <AlertDialogDescription>
 *     Are you sure you want to proceed with this action?
 *   </AlertDialogDescription>
 * </AlertDialogHeader>
 */
export const AlertDialogHeader = ({
  className,
  ...props
}: AlertDialogHeaderProps) => (
  <div className={header({ className })} {...props} />
);
 
AlertDialogHeader.displayName = 'AlertDialogHeader';
 
type AlertDialogTitleRef = React.ElementRef<typeof Title>;
type AlertDialogTitleProps = React.ComponentPropsWithoutRef<typeof Title>;
 
/**
 * AlertDialogTitle component for the AlertDialog that displays the dialog title.
 *
 * @param {AlertDialogTitleProps} props - Additional props to pass to the alert dialog title.
 *
 * @example
 * <AlertDialogTitle>Confirm Action</AlertDialogTitle>
 */
export const AlertDialogTitle = forwardRef<
  AlertDialogTitleRef,
  AlertDialogTitleProps
>(({ className, ...props }, ref) => (
  <Title ref={ref} className={title({ className })} {...props} />
));
 
AlertDialogTitle.displayName = Title.displayName;
 
type AlertDialogDescriptionRef = React.ElementRef<typeof Description>;
type AlertDialogDescriptionProps = React.ComponentPropsWithoutRef<
  typeof Description
>;
 
/**
 * AlertDialogDescription component for the AlertDialog that provides additional information.
 *
 * @param {AlertDialogDescriptionProps} props - Additional props to pass to the alert dialog description.
 *
 * @example
 * <AlertDialogDescription>
 *   Are you sure you want to proceed with this action?
 * </AlertDialogDescription>
 */
export const AlertDialogDescription = forwardRef<
  AlertDialogDescriptionRef,
  AlertDialogDescriptionProps
>(({ className, ...props }, ref) => (
  <Description ref={ref} className={description({ className })} {...props} />
));
 
AlertDialogDescription.displayName = Description.displayName;
 
type AlertDialogFooterProps = React.HTMLAttributes<HTMLDivElement>;
 
/**
 * AlertDialogFooter component for the AlertDialog that contains action buttons.
 *
 * @param {AlertDialogFooterProps} props - Additional props to pass to the alert dialog footer.
 *
 * @example
 * <AlertDialogFooter>
 *   <AlertDialogCancel>Cancel</AlertDialogCancel>
 *   <AlertDialogAction>Confirm</AlertDialogAction>
 * </AlertDialogFooter>
 */
export const AlertDialogFooter = ({
  className,
  ...props
}: AlertDialogFooterProps) => (
  <div className={footer({ className })} {...props} />
);
 
AlertDialogFooter.displayName = 'AlertDialogFooter';

Update import paths

Update the @kosori/ui import paths to fit your project structure, for example, using ~/components/ui.

Usage

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '~/components/ui/alert-dialog';
<AlertDialog>
  <AlertDialogTrigger>Open</AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
      <AlertDialogDescription>
        This action cannot be undone. This will permanently delete your account
        and remove your data from our servers.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Continue</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>

On this page