Overlays

Modal

Centered modal dialog shell built on the native dialog element with focus capture, restoration, and dismissal handling.

import { Modal } from '@lostgradient/cinder/modal';
overlaydialog
01

Overview

Generic modal shell for rich content, forms, and structured workflows. Use the more specialised components when the content fits their narrower contract.

Choosing this component

  • Presenting rich or structured content (forms, multi-step wizards, detail views) inside a blocking overlay.
  • Collecting structured input — especially when multiple fields or widgets are involved.
  • Displaying content that requires user interaction before the page can continue, but where the interaction is more than a simple yes/no.

Choosing something else

  • Two-action confirm/cancel prompts — use ConfirmDialog instead. It handles autofocus on the cancel button, aria-describedby, and the destructive-variant button automatically.
  • Urgent blocking acknowledgements that must not be dismissed by Escape or backdrop click — use AlertDialog instead.
  • Navigation — use a page transition or router link instead. Modals break the browser's back-button mental model.
  • Persistent side content — use a Drawer or Sidebar so the content stays visible while the user works.
  • Displaying information that does not require a decision — use a Popover or inline content instead.

Dialog model

Cinder provides three dialog-level components with distinct interaction contracts.

Modal is the generic shell. It handles focus capture/restore, body scroll lock, Escape dismissal, backdrop dismissal, and an optional close button. All three dismissal affordances are on by default (dismissOnBackdropClick, dismissOnEscape, closeButtonVisible). Use Modal when the content is richer than a simple prompt.

ConfirmDialog is a preset for user-initiated binary decisions. It composes Modal + two Buttons, defaults focus to the cancel button (the industry-standard guard against accidental destructive confirms), and wires aria-describedby automatically. Escape, backdrop click, and the close-X all fire onCancel. Use it for "Delete account?", "Discard changes?", and similar two-action prompts.

AlertDialog is a preset for urgent, blocking acknowledgements. It renders Modal with role="alertdialog", dismissOnBackdropClick={false}, dismissOnEscape={false}, and no close button. The user must click an explicit action button to proceed. Use it for session expiry and system-level errors — cases where the system surfaces a condition that must be acknowledged before continuing. For user-initiated actions (even high-impact ones), use ConfirmDialog instead.

The role prop and alertdialog

Modal accepts role="alertdialog" directly. This is intentional: some applications need to compose their own sticky dialog outside the AlertDialog preset (for example, a dialog with richer body content than AlertDialog's plain-text description prop allows).

When composing role="alertdialog" on Modal directly:

  • Set dismissOnBackdropClick={false} and dismissOnEscape={false} — otherwise the urgent-blocking contract is broken.
  • Set closeButtonVisible={false} — a close-X contradicts the "must acknowledge" intent.
  • Pass describedById pointing at a descriptive element in the body — aria-describedby is required for alertdialog.

If the content fits the plain-text description constraint, prefer AlertDialog over composing Modal + role="alertdialog" manually.

Related components

  • ConfirmDialog — pre-wired confirm/cancel variant built on Modal. Use for binary decisions.
  • AlertDialog — sticky alert dialog that cannot be dismissed by Escape or backdrop click. Use for urgent acknowledgements.
  • Drawer — side-anchored overlay for supplementary content.
  • Sheet — bottom-anchored overlay for mobile-style interactions.
  • Popover — non-blocking floating panel for contextual content.

Usage

svelte
<script lang="ts">
  import Modal from '@lostgradient/cinder/modal';
</script>

<Modal />
Live preview
02

When to use

Use when
  • Presenting rich or structured content that requires user interaction before returning to the page — forms, multi-step wizards, detail views.
  • Collecting structured input (forms, multi-field workflows) inside an overlay.
Avoid when
  • Only a two-action confirm/cancel prompt is needed — use confirm-dialog instead.
  • An urgent blocking acknowledgement is needed — use alert-dialog instead.
  • Showing side-anchored navigation or settings — use a drawer instead.
  • Presenting a small contextual surface anchored to a trigger — use a popover or sheet instead.
03

Examples

Basic modal

A modal used as a generic content shell — in this case an invite form with structured fields.

Overflowing modal

A modal body with enough content to scroll.

Modal with form

A modal whose first input carries autofocus; the native dialog focuses it on open.

04

Props

Props for modal
Name Type Default Required Bindable Description
open boolean false bind Controls whether the modal is open; bindable for controlled usage.
title text req Text rendered as the modal's visible heading and used as its accessible label.
role discriminated-union 'dialog' ARIA role applied to the underlying dialog element. Default dialog.
dismissOnBackdropClick boolean true When true, clicking the backdrop outside the modal panel dismisses it. Default true.
dismissOnEscape boolean true When true, pressing Escape dismisses the modal. Default true.
closeButtonVisible boolean true When true, renders the close button in the upper corner of the modal panel. Default true.
children snippet req
footer snippet
triggerRef HTMLElement | null null
describedById text When set, applied as aria-describedby on the underlying <dialog>. Pass a short, plain description ID only.
onDismiss () => void Fired on user-initiated dismissal. Includes: Escape key (native dialog 'cancel' event), backdrop click, and the close-X button. EXCLUDES: parent-driven open = false. Callbacks are not awaited and thrown callbacks do not block close.