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.
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.
Sizes
Panel widths via the Popup's size prop.
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
Modal.Root
Groups the parts and owns the open state (controlled or uncontrolled). Renders no element of its own.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Initial open state when uncontrolled. |
onOpenChange | (open: boolean) => void | — | Called whenever the open state should change. |
Modal.Trigger
A LoamUI Button that opens the dialog; all native <button> props are forwarded.
| Prop | Type | Default | Description |
|---|---|---|---|
render | element | (props) => node | — | Substitute your own element as the trigger; it receives the invoker wiring. |
Modal.Popup
The native <dialog>, opened with showModal(); all native <dialog> props are forwarded.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Panel width (24/32/44rem). |
alert | boolean | false | Renders role="alertdialog" with no light dismiss (Escape still closes), for destructive confirmations. |
Modal.Title
The dialog's heading (an <h2>), wired to the dialog via aria-labelledby; native heading props are forwarded.
Modal.Description
Supporting text, wired to the dialog via aria-describedby; native <p> props are forwarded.
Modal.Close
A LoamUI Button that closes the dialog; compose as many as you need (confirm, cancel, ×). Native <button> props are forwarded.
| Prop | Type | Default | Description |
|---|---|---|---|
render | element | (props) => node | — | Substitute your own element; it receives the close wiring. |