Overlays and modals

Dialog
v0.3.17
Documentation Under Review

A general-purpose modal component for interrupting workflow with contextual content requiring explicit user action. Built on Radix UI primitives with focus management, Escape key handling, and accessible naming out of the box.

Prefer AI-assisted development?

This documentation is available via the Catalyst MCP Server. Learn how to connect →

Catalyst Dialog extends Radix UI's Dialog primitive with PMI design tokens, entry animations, and a backdrop blur overlay — giving you a production-ready modal with focus trapping and accessible semantics out of the box.

Preview

Installation

npm install @pmi/catalyst-dialog
import {
  DialogRoot,
  DialogTrigger,
  DialogPortal,
  DialogOverlay,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from '@pmi/catalyst-dialog';

Setup

The Dialog provides a Tailwind preset for overlay colors and entry animations. Add it to tailwind.config.ts:

import tailwindDialogPreset from '@pmi/catalyst-dialog/tailwind.config';

export default {
  presets: [tailwindDialogPreset],
  // ...
};

Common Patterns

Tertiary Action

Place a ghost Cancel on the left and primary/secondary actions on the right.

Preview

Scrollable Content

Use max-h-[95vh] and overflow-y-auto on the body area for long content.

Preview

API Reference

Dialog is a compound component built on Radix UI primitives. The sections below summarize the API surface for each part.

DialogRoot

Root container that manages open/closed state. Accepts all standard Radix Dialog Root props.

DialogTrigger

Element that opens the dialog. Accepts all standard Radix Dialog Trigger props. Use asChild to render your own element.

DialogPortal

Renders the dialog into a portal outside the current DOM tree. Accepts all standard Radix Dialog Portal props.

DialogOverlay

Semi-transparent backdrop behind the dialog. Forwards ref to HTMLDivElement. Accepts all standard Radix Dialog Overlay props.

DialogContent

Main content container. Forwards ref to HTMLDivElement. Accepts all standard Radix Dialog Content props.

DialogTitle

Accessible title for the dialog. Forwards ref to HTMLHeadingElement. Accepts all standard Radix Dialog Title props.

DialogDescription

Supporting description below the title. Forwards ref to HTMLParagraphElement. Accepts all standard Radix Dialog Description props.

DialogClose

Button to close the dialog. Accepts all standard Radix Dialog Close props. Use asChild to render your own element.

Accessibility

Dialog is designed to meet WCAG 2.2 AA standards. Focus management and ARIA semantics are inherited from Radix UI.

Keyboard Interactions

KeyAction
EscapeCloses the dialog and returns focus to the trigger
TabCycles focus through interactive elements within the dialog

ARIA

  • aria-labelledby is automatically wired to DialogTitle, providing the accessible name — inherited from Radix.
  • aria-describedby is automatically wired to DialogDescription — inherited from Radix.
  • Focus is trapped inside the dialog when open and restored to the trigger on close.
  • Always include a visible close affordance (e.g. DialogClose wrapping a button with aria-label="Close") so keyboard and pointer users can dismiss the dialog.
  • Icon-only close buttons must include <span className="sr-only">Close</span> or aria-label for screen readers.

See the Radix Dialog accessibility docs for inherited baseline behavior.

Choosing the Right Component

Use Dialog for actions that require explicit user confirmation before proceeding. Reach for a different primitive when:

If you need…Use instead
A two-button confirmation for a destructive or irreversible actionAlert Dialog
A mobile-optimized bottom sheetDrawer
A side panel that slides in from the edgeSheet
A small contextual overlay anchored to a trigger elementPopover

On this page