Dialog

Dialog

A modal window layered over the page, built on Base UI. A centered card with header, content and footer in three width presets.

Playground

size
showCloseButton
<Dialog>
  <DialogTrigger render={<Button variant="outline">Open dialog</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Dialog title</DialogTitle>
      <DialogDescription>
        A short description of the dialog contents.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <Button>Save changes</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Preview

DialogTrigger opens the dialog – pass your button via the Base UI render prop. DialogContent portals the card over a dimmed overlay and includes a top-right close button by default.

<Dialog>
  <DialogTrigger render={<Button variant="outline">Open dialog</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Dialog title</DialogTitle>
      <DialogDescription>
        A short description of the dialog contents.
      </DialogDescription>
    </DialogHeader>
    <p className="text-sm text-muted-foreground">
      This is the main content of the dialog.
    </p>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <Button>Save changes</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Installation

npx shadcn@latest add https://espresso-base-ui.vercel.app/r/dialog.json

Usage

import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogOverlay,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
<Dialog>
  <DialogTrigger render={<Button variant="outline">Open</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
      <DialogDescription>Description</DialogDescription>
    </DialogHeader>
    <DialogFooter showCloseButton>
      <Button>Confirm</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Sizes

size on DialogContent sets the width preset: sm (max-w-sm), default (max-w-md) and lg (max-w-2xl) – all clamp to the viewport on small screens.

<DialogContent size="sm">...</DialogContent>
<DialogContent size="default">...</DialogContent>
<DialogContent size="lg">...</DialogContent>

Destructive confirmation

Compose DialogClose with the render prop to make any button dismiss the dialog – a common pattern for cancel/confirm footers.

<Dialog>
  <DialogTrigger render={<Button variant="destructive">Delete account</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Are you absolutely sure?</DialogTitle>
      <DialogDescription>
        This action cannot be undone. This will permanently delete your
        account.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <DialogClose render={<Button variant="outline">Cancel</Button>} />
      <DialogClose render={<Button variant="destructive">Delete</Button>} />
    </DialogFooter>
  </DialogContent>
</Dialog>

Without close button

showCloseButton={false} hides the built-in top-right close control when dismissal should go through an explicit action.

<DialogContent showCloseButton={false}>
  <DialogHeader>
    <DialogTitle>Custom close handling</DialogTitle>
    <DialogDescription>
      The top-right close button is hidden – dismiss via the footer action.
    </DialogDescription>
  </DialogHeader>
  <DialogFooter>
    <DialogClose render={<Button>Got it</Button>} />
  </DialogFooter>
</DialogContent>

API reference

Dialog is the Base UI root and accepts its props – open, defaultOpen, onOpenChange, modal and dismissible. Interactive parts (DialogTrigger, DialogClose) support the Base UI render prop to swap in your own element; when the rendered element is not a native button, also pass nativeButton={false}.

DialogContent

PropTypeDefaultDescription
size"sm" | "default" | "lg""default"Width preset: max-w-sm, max-w-md or max-w-2xl (reflected as data-size).
showCloseButtonbooleantrueRender the ghost icon close button in the top-right corner.

DialogFooter

PropTypeDefaultDescription
showCloseButtonbooleanfalseAppend an outline "Close" button that dismisses the dialog after your custom actions.
ComponentDescription
DialogTriggerOpens the dialog (data-slot="dialog-trigger"); compose your button via the render prop.
DialogContentCentered popup card (data-slot="dialog-content") rendered in a portal above the overlay, with zoom/fade animations.
DialogOverlayDimmed backdrop (data-slot="dialog-overlay") rendered automatically by DialogContent.
DialogHeaderVertical stack for title and description (data-slot="dialog-header").
DialogTitleAccessible heading (data-slot="dialog-title") announced when the dialog opens.
DialogDescriptionMuted supporting copy (data-slot="dialog-description") with underlined links.
DialogFooterAction row (data-slot="dialog-footer"): stacked on mobile, right-aligned on desktop.
DialogCloseDismisses the dialog (data-slot="dialog-close"); compose any button via the render prop.
DialogPortalPortals dialog parts to the document body (data-slot="dialog-portal"); used internally by DialogContent.

The dialogContentVariants cva helper is also exported for building custom dialog surfaces with the same size classes.

Accessibility & styling hooks

Base UI renders the popup with role="dialog" and aria-modal, wires aria-labelledby / aria-describedby to DialogTitle and DialogDescription, traps focus while open, and closes on Escape or backdrop click. Every part exposes a data-slot attribute, the content reflects its size as data-size, and open/close state is exposed as data-open / data-closed for animation and styling hooks.

Search documentation

Search the component docs