Skip to main content

What it is

A surface that sits on top of the page and blocks interaction with everything behind it until the reader finishes or cancels. It ships with a title row, a content area with configurable top and bottom dividers, and a footer carrying up to three buttons — an optional left-side action, Cancel, and Save — so a caller assembles a complete confirmation or edit flow from one component rather than building the layout by hand each time.

Live example

Exports

The package’s Dialog export is a different, unstyled primitive, not this component. This page documents the real export Modal. Source publishes a named anti-pattern story (DoNotUse_RawDialog) stating directly that importing the raw primitive loses the standardized title/action layout, the sizing presets, the dividers, and the padding this page documents. Import Modal for everything this page describes. See TITAN-DIV-27.
Hand-confirmed from source — no prop emitter has run for this component yet.

Choose Dialog when

  • The reader must make a decision — confirm, cancel, or complete a short task — before anything else on the page should be usable.
  • The task is short enough to finish in an overlay rather than navigating to its own page.
  • Losing the reader’s place on the page behind it is an acceptable cost for the interruption.

Choose something else when

Anatomy

Variants, sizes, and states

Six size presets, confirmed against both source and the token file: sm, md (default), lg, xl, xxl, and fullscreen. Each sets both a width (or 100% for fullscreen) and a content minimum height — see Tokens for the literal values. Published stories additionally demonstrate: hiding the entire footer, a custom left-button color, custom close-button props for testing, and disabled dividers with padding removed to host tabbed content instead of prose.

Edge and failure states

  • No left button unless both leftButtonAction and leftButtonText are supplied. Confirmed from source — the left button area renders empty otherwise, leaving visible empty space in the footer’s flex layout rather than collapsing.
  • disableConfirmButton disables Save without hiding it — confirmed by the component’s own test. A reader sees the option and cannot use it, with no stated reason shown by the component itself.
  • Closing behavior with no onClose handler is not a no-op error — the prop defaults to an empty function, so a Dialog missing onClose fails silently rather than throwing; the Cancel button and backdrop dismiss visually but change nothing in the caller’s state.

Tokens

Hand-confirmed from Modal.overrides.ts and component.tokens.json — no per-component token emitter exists yet for this concept, so this table is hand-confirmed rather than generated.

Composition

Dialog is a standalone overlay — it does not compose into Form’s field pattern. A published story shows Tabs rendered inside the content area with dividers disabled and padding cleared, so tabbed content is a supported composition, not just prose or a single form.

Content

Accessibility

  • The underlying primitive provides the page-blocking and focus-containment behavior; no test in source specifically asserts focus is trapped inside an open Dialog or restored to the trigger on close, so that behavior, while expected of the pattern, is unconfirmed at the Titan layer.
  • The title renders inside a span with a data-testid, not as a heading element bound to the dialog via aria-labelledby — whether the title is programmatically associated with the dialog for assistive technology is unconfirmed from source.
  • Confirmed from the test suite: Cancel and Save render as real, focusable, nameable buttons, and disableCloseButton / disableConfirmButton produce a genuinely disabled button state.

Constraints

Known issues

Dialog: open issues

Divergences, open decisions, and undocumented gaps for Dialog.

Why it works this way

The three-button footer is a fixed contract, not a layout convention teams re-invent. Left action, Cancel, and Save are named, positioned, and colored by the component itself — a caller supplies text and handlers, not markup. That is also why an anti-pattern story exists here and not on every component: the raw primitive underneath renders visually similarly enough that bypassing Modal produces something that looks plausible in review but silently drops the sizing presets, the divider tokens, and the footer layout this page documents.

Status

No lifecycle metadata exists. There is no status, since, deprecated, or replacedBy field on a Titan component, so this table cannot report when an export arrived or whether it is on the way out.
Hand-confirmed from utilization.md — no utilization emitter has run for this component yet. Roughly 99 usages across 24 applications, the heaviest being ai-model-management (12), ai-agent-studio (11), dashboard-header (11), agent-management-v2 (10), and manage-integrations (10) — overwhelmingly confirmation and edit flows (archive, delete, rename, share, schedule).
  • Drawer — for a task that should leave the page behind it visible
  • Menu — for choosing among several actions rather than confirming one
Last modified on September 2, 2026