Morpha UI

Dialog

A modal overlay for focused tasks and decisions.

Overview

A dialog is a modal surface that appears in front of app content to provide critical information or prompt for a decision. It is built on the Base UI Dialog primitive — focus trap, scroll-lock and Esc dismissal are handled for you — and styled to the Material-3 surface: surface-container-high, 28px corners and the elevation-3 shadow.

Compose it from DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription and DialogFooter. Actions are plain Buttons — the basic dialog has no close "X"; it relies on the footer actions.

$ npx morpha-ui add dialog

Composition

<Dialog>
  <DialogTrigger render={<Button variant="tonal">Open</Button>} />
  <DialogContent>
    <DialogHeader>
      <DialogIcon /> {/* optional, align="center" only */}
      <DialogTitle />
      <DialogDescription />
    </DialogHeader>
    <DialogBody /> {/* optional — the scrolling region */}
    <DialogFooter>
      <DialogClose render={<Button variant="text">Cancel</Button>} />
    </DialogFooter>
  </DialogContent>
</Dialog>

The fullscreen variant swaps the header for DialogTopBar (leading close, flexible title, trailing action) and keeps DialogBody for the content.

Examples

With icon (centered)

Set align="center" on DialogContent and add a DialogIcon above the title. The headline and supporting text center to match the Figma "icon" layout.

Without headline

Drop the visible title when the supporting text says everything (the Figma "show title = false" variant). Keep a DialogTitle with sr-only so the dialog still has an accessible name.

Single action

Acknowledgement dialogs take one action instead of the usual pair — the Figma "show action 2 = false" variant. The footer keeps the same right-aligned rhythm.

With close button

Pass showCloseButton to add the top-right "X" (an IconButton). It is off by default: the Figma dialog dismisses through its actions.

With a form

Wrap the header, fields and footer in a <form> and let the submit button close the dialog. Fields use the standard Field / InputGroup parts on the same 24px gutter as the header.

Scrollable content

Put long content in DialogBody; it scrolls while the header and footer stay fixed. Add divided to draw the dividers that separate the scroll region.

Controlled

Drive the dialog yourself with open / onOpenChange — useful when an action must run before it closes, or when there is no trigger to click at all.

Not subscribed yet.

Alert (non-dismissible)

Pass dismissible={false} for confirmations that must be answered: clicking the scrim or pressing Esc no longer closes it, and the content is exposed as role="alertdialog". Pair it with a destructive action.

Full-screen

variant="fullscreen" fills the viewport (no radius or shadow) and slides up from the bottom — the mobile pattern. Use DialogTopBar for the header (leading close, flexible title, trailing action) and DialogBody for the content.

RTL

Wrap the app in DirectionProvider and set dir="rtl". The header, supporting text and the footer actions all mirror — the paddings are logical, not physical. Because the content is portalled, set dir on DialogContent too (or on <html>).

Coming from shadcn? There is no separate alert-dialog component — pass dismissible={false} to DialogContent for alert semantics (role="alertdialog", no outside-click / Esc close).

Installation

Morpha UI components are distributed via the Morpha CLI: npx morpha-ui add dialog.

npx morpha-ui add dialog

API Reference

DialogContent adds the props below; all Base UI Dialog.Popup props are forwarded. The other parts — DialogTrigger, DialogHeader, DialogIcon, DialogBody, DialogFooter, DialogTopBar, DialogTitle, DialogDescription and DialogClose — forward their Base UI / div props. DialogBody takes one extra prop, divided, which draws the top/bottom dividers around the scrolling region.

Prop

Type

The Dialog root:

Prop

Type

Accessibility

  • A DialogTitle is required (wrap it in sr-only if you don't want it shown) so the dialog has an accessible name.
  • Link explanatory text with DialogDescription — Base UI wires aria-describedby automatically when one is present, and omits it otherwise (no workaround needed for layouts without one).
  • Focus is trapped while open and restored on close; Esc dismisses the dialog (handled by Base UI) — unless dismissible={false}, which keeps it open and marks it role="alertdialog".
  • The enter animation fades and scales from 0.95; under prefers-reduced-motion only the fade remains (no zoom or slide).

The dialog content is rendered in a portal on document.body, so inside the preview it follows the site theme rather than the frame's light/dark toggle.

On this page