Modal

Blocking dialog with header, body, and footer actions.

Examples

Properties

PropertyAttributeDescriptionType nameTypeDefault
openopenWhen set, opens the dialog (`showModal`).booleanbooleanfalse
showModalshow-modalAlias for `open`.booleanbooleanfalse
titletitleHeader title when the `title` slot is empty.stringstring""
subtitlesubtitleSecondary line under the title.stringstring""
titleTagtitle-tagHeading element for `title` (default `h5`).DuoModalTitleTag"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "div""h5"
sizesize`s` | `m` | `l` | `xl` | `fullscreen` (default `m`).DuoModalSize"s" | "m" | "l" | "xl" | "fullscreen""m"
showCloseshow-closeRenders a header close control. Omit on desktop-only Figma layouts.booleanbooleantrue
isMobileis-mobileShows close and stacks footer actions in a column (column-reverse).booleanbooleanfalse
mobilemobileAlias for `is-mobile`.booleanbooleanfalse
mobileFootermobile-footerStacks footer actions vertically (column-reverse) without forcing the close button.booleanbooleanfalse
accessibleLabelaria-labelAccessible name when no visible title (rare; prefer `title` / `title` slot).string | undefinedstring | undefined—

Slots

NameDescription
defaultModal body content.
titleCustom title markup (overrides the `title` attribute).
headerFull header region (overrides built-in title / subtitle / close).
footerAction buttons (e.g. `<duo-button>`).

Methods

Method nameParametersDescription
show() => voidN/AProgrammatically open (sets `open` and `show-modal`).
hide() => voidN/AProgrammatically close without emitting `close` (use click handlers that call `#emitClose` instead).

Usage

Modal presents a centered, blocking dialog for confirmations, short forms, or focused tasks. It uses the native <dialog> element and mirrors legacy reactstrap Modal / ModalHeader / ModalBody / ModalFooter from Storybook React.

<duo-modal open title="Delete item?" subtitle="This cannot be undone.">
<p>Your data will be removed permanently.</p>
<duo-button slot="footer" variant="default" outline>Cancel</duo-button>
<duo-button slot="footer" variant="danger">Delete</duo-button>
</duo-modal>

Do

  • Control visibility with open (or legacy show-modal) and listen for close to update app state.
  • Put primary actions in the footer slot as real buttons or links.
  • Provide title (or the title slot) so assistive tech gets aria-labelledby.
  • Set show-close="false" on desktop-only layouts that match Figma (footer / Escape / backdrop only).

Don’t

  • Don’t use for non-blocking hints — use Banner or inline patterns.
  • Don’t nest modals without a strong reason — prefer a single focused step.
  • Don’t rely on the modal as the only way to dismiss destructive flows without an explicit footer action.

Sizes

Duo T-shirt sizes (s, m, l, xl) — same naming as Button and Empty state, not Bootstrap sm/md.

SizeWhen to use
sCompact confirmations; footer stacks (mobile / narrow).
mDefault (~482px).
lWider content or two-column body.
xlFull-width forms or rich previews.

Set fullscreen for viewport-filling flows (e.g. multi-column order wizards). The body becomes a flex column with nested scroll regions. When fullscreen is active, the host exposes --duo-modal-header-height for sizing side panels.

Migration

See packages/ui/src/components/modal/MIGRATION.md in the repository for a step-by-step guide from the legacy React modal, including a Bootstrap → Duo size mapper (sm → s, md → m, etc.).

Events

The host fires a bubbling, composed close event with detail.reason: escape, backdrop, or close-button.