Modal
A dialog that renders in a portal over the page, traps focus while open, and
closes on Escape or a backdrop click. Composed from ModalHeader,
ModalTitle, ModalBody, and ModalFooter.
Import
import {
Modal,
ModalHeader,
ModalTitle,
ModalBody,
ModalFooter,
} from '@metatoy/bootstrap-styled'; Launch a modal
Modal is controlled — you own the show state and pass onHide to close
it. The button below toggles that state.
The full controlled pattern:
import { useState } from 'react';
import { Modal, ModalHeader, ModalTitle, ModalBody, ModalFooter, Button, CloseButton } from '@metatoy/bootstrap-styled';
function Example() {
const [show, setShow] = useState(false);
return (
<>
<Button onClick={() => setShow(true)}>Open modal</Button>
<Modal show={show} onHide={() => setShow(false)} centered>
<ModalHeader>
<ModalTitle>Modal title</ModalTitle>
<CloseButton onClick={() => setShow(false)} />
</ModalHeader>
<ModalBody>Modal content.</ModalBody>
<ModalFooter>
<Button variant="secondary" onClick={() => setShow(false)}>Close</Button>
<Button onClick={() => setShow(false)}>Save changes</Button>
</ModalFooter>
</Modal>
</>
);
} Overlay scope. The open modal renders through a portal and its backdrop covers the entire viewport (not just this demo card) — that is the real component behavior. Press Escape or click the dimmed area to dismiss it.
Dialog surface
The Modal* parts are plain styled elements, so you can render the dialog
surface inline (without the overlay) to preview its structure:
Sizes, centering & static backdrop
size="sm" | "lg" | "xl" sets the dialog max-width, centered vertically
centers it, and staticBackdrop keeps it open when the backdrop is clicked.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| show● | boolean | — | — |
| onHide● | () => void | — | — |
| size | 'sm' | 'lg' | 'xl' | — | — |
| centered | boolean | — | — |
| staticBackdrop | boolean | — | Don't close on backdrop click. |
| children | React.ReactNode | — | — |
The subcomponents — ModalHeader, ModalTitle, ModalBody, ModalFooter —
are styled elements that accept all native attributes for their tag
(<div> / <h5>).
Theming
The dialog surface reads the global surface tokens rather than a per-component
namespace: --bs-body-bg and --bs-body-color for the fill, plus
--bs-border-color-translucent, --bs-border-radius-lg, and --bs-box-shadow
for the frame. Header and footer dividers use --bs-border-color. Override any
of these on an ancestor to re-skin the dialog; because the modal is portaled,
the library re-applies the active theme’s variables inside the portal so your
tokens still reach it.
Accessibility
The dialog is rendered with aria-modal="true" and a dialog role, and focus is
trapped inside while it is open (and restored to the trigger on close). Provide
a ModalTitle and wire a CloseButton (which ships an accessible label) to
onHide. Escape closes the modal unless you set staticBackdrop.
Open in Ladle
Explore the source component’s story in the library workshop: Modal · Ladle