Dialog

Loading...

Installation

Add the component with the CLI.

npx shadcn@latest add @intentui/dialog

Composed components

When you install this component via the CLI, it automatically loads all composed components, so you don’t need to add them individually.

Manual installation

Install the dependencies, then copy the component source into your project.

npm install react-aria-components @heroicons/react cn

Anatomy

import { Button } from "@/components/ui/button"
import { Dialog, DialogBody, DialogClose, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<DialogTrigger>
  <Button>Open Dialog</Button>
  <Dialog>
    <DialogHeader>
      <DialogTitle>Dialog Title</DialogTitle>
      <DialogDescription>Dialog Description</DialogDescription>
    </DialogHeader>
    <DialogBody>Dialog Body</DialogBody>
    <DialogFooter>
      <DialogClose>Close</DialogClose>
      <Button>Confirm</Button>
    </DialogFooter>
  </Dialog>
</DialogTrigger>

Examples

Alert dialog

Use role="alertdialog" for a critical message that requires an explicit response.

Loading...

Alert dialogs cannot be dismissed by clicking outside by default, and the close icon is hidden. Provide an explicit action such as Cancel.

<Dialog role="alertdialog" />

Controlled

You can control the dialog programmatically.

Loading...

Sizes

The dialog defaults to md. Available sizes are 2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, and fullscreen.

Loading...

Dialog overlay styles

The overlay uses a subtle 1px blur by default. You can increase it or disable it entirely.

<DialogTrigger>
  <Button intent="outline">Rename</Button>
  <Dialog overlay={{ className: "backdrop-blur-2xl" }}>

If you want to turn it off, use backdrop-blur-none. If you do not need any blur at all, the recommended approach is to remove the blur class from the component defaults.

-"bg-background/15 backdrop-blur-[1px] motion-reduce:backdrop-blur-none",
+"bg-background/15",

Or, you can override it per instance from the component usage:

<DialogTrigger>
  <Button intent="outline">Rename</Button>
  <Dialog overlay={{ className: "backdrop-blur-none" }}>

Sticky

Use DialogBody for scrollable content while the header and footer stay visible.

Loading...

Nested

Open a dialog from within another dialog to present a nested confirmation.

Loading...

Pass a string to DialogHeader to render it as the title:

<DialogHeader>
  Title
</DialogHeader>

Use the title and description props to configure the header:

<DialogHeader title='Title' description='Description' />

Triggered by menu

You can also trigger the dialog by clicking on a menu item.

Loading...

Extract the dialog into a component to reuse it for multiple menu actions.

interface DialogActionProps {
  state: string | null
  onOpenChange: () => void
  actionType: { description: string; action: () => void; confirmText: string; title: string }
  disabled: boolean
}

const DialogAction = (props: DialogActionProps) => (
  <Dialog isOpen={props.state !== null} onOpenChange={props.onOpenChange}>
    <DialogHeader>
      <DialogTitle>{props.actionType?.title}</DialogTitle>
      <DialogDescription>{props.actionType?.description}</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose>Cancel</DialogClose>
      <Button
        intent={props.state === "ban" ? "danger" : "primary"}
        className="min-w-24"
        isDisabled={props.disabled}
        onPress={props.actionType?.action}
      >
        {props.disabled ? <Loader variant="spin" /> : props.actionType?.confirmText}
      </Button>
    </DialogFooter>
  </Dialog>
)

Pass the current action and loading state to the dialog:

<DialogAction
  state={state}
  onOpenChange={closeDialog}
  actionType={actionType(state)}
  disabled={loading}
/>

With that, now we can modify the actionType function to return the initial state.

const actionType = (t: string | null) => {
  const initialsState = {
    title: '',
    description: '',
    confirmText: '',
    action: () => {}
  }

  switch (t) {
    case 'delete': ...
    case 'ban': ...
    case 'restore': ...
    default:
      return initialsState
  }
}

Component API

DialogTrigger

DialogTrigger extends the React Aria Components <DialogTrigger> component.

Dialog

Dialog extends the React Aria Components <ModalOverlay> component.

classNamestring
isOpenboolean
onOpenChange(isOpen: boolean) => void
isDismissableboolean
Default: true, except for alertdialog
role"dialog" | "alertdialog"
Default: dialog
closeButtonboolean
Default: true
overlayPick<ModalOverlayProps, "className">
sizekeyof typeof sizes
Default: md

DialogBody

DialogBody extends the native <div> element.

classNamestring

DialogCloseIcon

DialogCloseIcon renders a React Aria Button with the close slot. Dialog renders it automatically when closeButton and isDismissable are enabled.

classNamestring
isDismissableboolean | undefined

DialogClose

DialogClose extends the Intent UI <Button> component.

classNamestring
intent"primary" | "secondary" | "warning" | "danger" | "success" | "outline" | "plain"
Default: plain

DialogDescription

DialogDescription renders a native <p> element.

classNamestring

DialogFooter

DialogFooter extends the native <div> element.

classNamestring

DialogHeader

DialogHeader extends the native <div> element.

classNamestring
descriptionstring
titlestring

DialogTitle

DialogTitle extends the React Aria Components <Heading> component.

classNamestring
Design