Dialog
Dialog is a pure modal shell — it owns only the mechanics (portal to <body>, scroll-lock, backdrop, dismiss, focus-trap, ARIA) and renders whatever you
put inside. For the common title + message + Confirm/Cancel pattern, reach for ConfirmDialog, which composes a Card on top of the shell.
ConfirmDialog — the common case
ConfirmDialog — custom body
Pass children to replace the message with your own content; the header and footer
stay.
Dialog — your own layout
Use Dialog directly to control the whole panel — e.g. your own Card with
a separator-less footer, or raw content with no Card at all.
Sizing — width / height
Both accept any CSS value — %, vw/vh, px, rem — and are capped to the viewport minus a 1rem inset so the panel never runs
off-screen. Omit either for content-sizing.
Controlling focus — onShow / onHide
By default the shell focuses the first focusable element (here, the input). onShow(ctx) hands you ctx.autoFocus (preset to the default selector) — retarget it to a selector
or element, or set false to skip. Below, onShow focuses the Close button instead of the input. (onHide(ctx) mirrors it with ctx.restoreFocus.)
What the shell handles
- • Top layer: portaled to
<body>— never clipped by an ancestor and never perturbs page layout. - • Scroll lock: background scroll is locked while open (scrollbar-width compensated — no sideways jump).
- • Dismiss: backdrop-click + Escape close it;
dismissible={false}for a must-decide modal. - • Focus: focus moves into the panel on open, is trapped (Tab
wraps), and returns to the trigger on close — all overridable via
onShow/onHide. - • Accessible:
role="dialog"+aria-modal; passaria-label/aria-labelledbythrough to the panel.