Skip to content
View as Markdown

Disclosures

Modal

A blocking dialog for must-complete tasks, built on the native <dialog> element and the browser's top layer.

Import

import { Modal } from "@loamui/core";

Usage

Every example has a CSStab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.

Basic usage

Compose the dialog from parts. The Popup is a native <dialog> opened with showModal(): top layer, backdrop, focus containment, Escape and focus restore all come from the browser.

Invite a teammate

They'll receive an email invitation to join your workspace.

Alert dialog (confirmation)

alert renders role="alertdialog": the backdrop doesn't light-dismiss (closedby="closerequest"; Escape still works), and autoFocus belongs on the least-destructive action so it is the default answer. Use for destructive or irreversible confirmations only.

Delete this file?

“report-final-v2.pdf” will be permanently deleted. This cannot be undone.

Sizes

Panel widths via the Popup's size prop.

A sm modal

The panel width comes from the size prop.

A md modal

The panel width comes from the size prop.

A lg modal

The panel width comes from the size prop.

Header with a close button

A header row with an × is a composition pattern, not configuration: compose Modal.Title and Modal.Close however your design needs.

Settings

Manage your workspace settings.

Guidance

When to use it

  • For blocking, must-complete tasks (confirmations of destructive actions, short focused forms) where the user should not interact with the page behind.
  • When losing the in-progress state would be costly, and the dialog protects it.

When not to

  • For supplementary content or quick actions that don't need to block, use Popover.
  • For anything long-form or multi-step, navigate to a page instead and keep the interaction in the page flow.
  • For non-essential announcements, use Alert in the page.

Accessibility

  • Built on the native <dialog> opened with showModal(): the browser provides the top layer, ::backdrop, real focus containment, Escape handling, and restores focus to the trigger on close. None of it re-implemented in JavaScript.
  • Modal.Title and Modal.Description automatically label and describe the dialog via aria-labelledby / aria-describedby.
  • Light dismiss (clicking the backdrop) uses the closedby attribute where supported, with a small feature-detected coordinate-check fallback elsewhere: no polyfills, per the browser support policy.
  • Body scroll is locked while open.

How it works

Destructive confirmations use the alert variant

The alert prop on Modal.Popup renders role="alertdialog" and sets closedby="closerequest": the backdrop stops light-dismissing, so a stray click cannot answer a destructive question; only an explicit choice or Escape closes it. Reserve it for decisions with consequences; an ordinary modal should stay casually dismissible.

Focus is the browser's to manage

showModal() moves focus into the dialog, contains it, and returns it to the trigger on close. Add autoFocus only when the dialog's task starts at a specific control, such as a name field in a rename dialog. Anything else fights behaviour screen-reader users rely on.

A modal is one task

If the content scrolls, needs sections, or asks more than one question, it has outgrown the dialog: make it a page. The dialog's value is that everything needed for the decision is visible at once.

Always render a Title

Modal.Title labels the dialog via aria-labelledby; it is what screen readers announce on open. A dialog without one is announced as, at best, "dialog": the user hears that something opened but not what it wants.

Parts