Modal
v0.4.1StableA `Card` centered in the viewport with a dimmed backdrop that blocks interaction with the rest of the page, built on [Radix `Dialog`](https://www.radix-ui.com/primitives/docs/components/dialog) for focus trapping, Escape-to-close, and outside-click-to-close. It has no opinion on what goes inside the panel — an optional `title` renders a header with a close button, otherwise just the `children` are shown.
A Card centered in the viewport with a dimmed backdrop that blocks
interaction with the rest of the page, built on Radix Dialog
for focus trapping, Escape-to-close, and outside-click-to-close. It has no
opinion on what goes inside the panel — an optional title renders a header
with a close button, otherwise just the children are shown.
size="fullscreen" drops the Card and fills the viewport on the lowest surface
tier: a top bar holds the title and the close button and children fill the
rest. It is for content that needs the whole screen, such as a lightbox. Pass
onCloseAutoFocus to choose where focus lands when the modal closes, and
closeLabel to translate the close button's name.
Pass footer for the dialog's action buttons: they sit below the content and stay
visible while the content scrolls under the panel's height cap, so a long form
never pushes Save off the screen. It is ignored by size="fullscreen".
For a panel that docks to an edge of the viewport instead — optionally
non-blocking — use @behivetech/atoms.drawer.
Usage
Examples
Open all 3 →Properties
Modal props
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Dialog content |
onClose* | () => void | — | Called when the modal is dismissed (backdrop click, Escape, or the close button) |
className | string | — | Additional class names to merge with the component root element |
closeLabel | string | Close | Accessible name of the close button, for translation; defaults to "Close" |
footer | ReactNode | — | Action buttons kept below the content. They stay visible while the content scrolls under the panel's height cap, so a long form never pushes Save off the screen. Ignored by `size="fullscreen"`, which has no panel. |
headingLevel | 1 | 2 | 3 | 4 | 5 | 6 | — | Which heading tag wraps `title` — same values as `Card`'s `headingLevel` prop |
icon | ReactNode | — | Optional icon rendered before the title in the header; ignored if `title` is omitted |
onCloseAutoFocus | ((event: Event) => void) | — | Called when focus is about to return to the element that was focused before the modal opened; call `event.preventDefault()` to move focus elsewhere. |
padding | "sm" | "md" | "none" | "lg" | — | Internal padding of the panel body — same values as `Card`'s `padding` prop |
size | "default" | "fullscreen" | default | `default` is a `Card` panel centered in the viewport. `fullscreen` fills the viewport with no `Card` panel: a top bar holds the `title` and the close button and `children` fill the rest, for content such as a lightbox. Fullscreen ignores `icon`, `padding` and `headingLevel`, and its title is not a heading. The close button is always there, with or without a title. |
title | ReactNode | — | Optional header title; omit to render no header and no close button |
Also accepts the native attributes of its root element (className, aria-*, event handlers, …).