Skip to content

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.

Open full source ↗

Props

PropTypeDefaultDescription
open / onOpenChangeboolean / fn—Controlled open state.
labelstring—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.

Works alongside