# Modal

## Overview

_[Design to fill]_

- **When to use**: _[Design to fill]_
- **When not to use**: _[Design to fill]_

## Anatomy

_[Design to fill]_

## Variants

_[Design to fill]_

## Props / API

Modal is a compound component built on Base UI's `Dialog`. Compose it from `Modal`, `Modal.Header`, `Modal.Header.Title`, `Modal.Header.Close`, `Modal.Content`, and `Modal.Footer`.

### `Modal`

Renders the dialog root, portal, backdrop, and popup. The popup carries `aria-modal="true"`.

| Prop           | Type                      | Default | Description                                                         |
| -------------- | ------------------------- | ------- | ------------------------------------------------------------------- |
| `open`         | `boolean`                 | -       | Controls whether the modal is open.                                 |
| `onOpenChange` | `(open: boolean) => void` | -       | Called when the open state should change (backdrop, escape, close). |
| `children`     | `React.ReactNode`         | -       | Modal content, typically the header, content, and footer parts.     |

### `Modal.Header`

Layout container for the title and close button. Extends `React.HTMLAttributes<HTMLDivElement>`; all standard `<div>` attributes are forwarded via `...rest`.

### `Modal.Header.Title`

Renders Base UI's `Dialog.Title`, containing the name of the dialog. Extends `React.HTMLAttributes<HTMLHeadingElement>`; all standard attributes are forwarded via `...rest`.

### `Modal.Header.Close`

Renders a ghost icon `Button` (`icon="cross"`) wrapped in Base UI's `Dialog.Close`, so it dismisses the modal. Ships with `aria-label="Close modal"`. Accepts `ButtonProps`; all Button props are forwarded and can override the defaults.

### `Modal.Content`

Layout container for the modal body. Extends `React.HTMLAttributes<HTMLDivElement>`; all standard `<div>` attributes are forwarded via `...rest`.

### `Modal.Footer`

Layout container for footer actions, typically Buttons. Extends `React.HTMLAttributes<HTMLDivElement>`; all standard `<div>` attributes are forwarded via `...rest`.

## States

- Closed
- Open

## Code examples

```tsx
import { Button, Modal } from "@mylighthouse/prism-react";
import { useState } from "react";

export default function ModalExample(): React.JSX.Element {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button buttonType="secondary" onClick={() => setOpen(true)}>
        Open Modal
      </Button>
      <Modal onOpenChange={setOpen} open={open}>
        <Modal.Header>
          <Modal.Header.Title>What&apos;s new in Lighthouse</Modal.Header.Title>
          <Modal.Header.Close />
        </Modal.Header>
        <Modal.Content>
          <p className="text-300--regular">
            Revenue reports can now be exported in Excel format with
            customizable column layouts.
          </p>
        </Modal.Content>
        <Modal.Footer>
          <Button buttonType="secondary" onClick={() => setOpen(false)}>
            Learn more
          </Button>
          <Button onClick={() => setOpen(false)}>Got it</Button>
        </Modal.Footer>
      </Modal>
    </>
  );
}
```

## A11y intent

_[Design to fill]_

- Built on Base UI's `Dialog`, so the popup exposes the `dialog` role and `aria-modal="true"`.
- Focus is trapped within the open dialog and returned to the trigger on close.
- `Escape` closes the modal, as does activating the backdrop or `Modal.Header.Close`.
- `Modal.Header.Title` renders `Dialog.Title`, giving the dialog its accessible name (`aria-labelledby`), so always include it.
- `Modal.Header.Close` ships an `aria-label="Close modal"` so the icon-only control has an accessible name.

## Cross-references

- **[Button](./button.md)**: used for `Modal.Header.Close` and typical `Modal.Footer` actions.
