Dialog
A modal with focus trap, Escape handling, scroll lock and an expo entrance.
Live — this one is real
Usage
import { useState } from "react";
import {
Button,
Dialog,
DialogTitle,
DialogBody,
DialogFooter,
DialogClose,
} from "mizu-ui";
export function Modal() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open dialog</Button>
<Dialog open={open} onOpenChange={setOpen} label="Archive notice">
<DialogClose />
<DialogTitle>Release when ready</DialogTitle>
<DialogBody>…</DialogBody>
<DialogFooter>
<Button onClick={() => setOpen(false)}>Close</Button>
</DialogFooter>
</Dialog>
</>
);
}
Source & setup
Import mizu-ui/styles.css once. Fonts are optional via mizu-ui/fonts.css. Override --mizu-* tokens or use className for local styling. Uses native React and CSS; install the package peers for root imports.
Inspect composite/Dialog.tsx
Source is included in the npm package under src/composite/Dialog.tsx.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| open / onOpenChange | boolean / fn | — | Controlled open state. |
| label | string | — | Accessible name for the dialog. |
Accessibility
Native showModal supplies background inertness and focus containment. Escape requests close, focus returns to the trigger and body scroll is locked. Local themes are preserved.
Motion
A CSS expo entrance communicates opening. Reduced motion removes the entrance.