# Dialog

## Overview

A modal overlay that interrupts the page flow to capture user attention for critical confirmations, data entry, or detailed views. Built on Radix UI Dialog with managed focus trapping, keyboard escape, and backdrop click-to-dismiss.

---

## When to Use

- Create / Edit forms that are supplementary to a list page (CRUD pattern)
- Short confirmation dialogs that need more detail than `AlertDialog`
- Detailed record previews without navigating away

## When NOT to Use

- **Irreversible destructive actions** — use `AlertDialog` instead (it has a required confirmation step).
- **Very large forms** with many fields — use a dedicated page route instead.
- **Mobile bottom panels** — use `Drawer` for better mobile UX.

---

## Anatomy

```
<Dialog>
  <DialogTrigger />         ← Button that opens the dialog
  <DialogContent size="md">
    <DialogHeader>
      <DialogTitle />
      <DialogDescription />
    </DialogHeader>
    <DialogBody />          ← Optional: scrollable middle, pins header/footer
    <DialogFooter />
  </DialogContent>
</Dialog>
```

---

## Props

### Dialog

| Prop           | Type                      | Description                |
| -------------- | ------------------------- | -------------------------- |
| `open`         | `boolean`                 | Controlled open state      |
| `onOpenChange` | `(open: boolean) => void` | Open/close handler         |
| `defaultOpen`  | `boolean`                 | Uncontrolled initial state |

### DialogContent

| Prop                   | Type                                                                         | Default | Description                                                              |
| ---------------------- | ---------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------ |
| `size`                 | `'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| '3xl' \| '4xl' \| '5xl' \| 'full'` | `'lg'`  | Width preset. `full` fills the viewport.                                 |
| `showClose`            | `boolean`                                                                    | `true`  | Whether to render the × close button (always pinned, never scrolls away) |
| `className`            | `string`                                                                     | —       | Additional CSS classes                                                   |
| `onPointerDownOutside` | `event => void`                                                              | —       | Intercept outside click                                                  |
| `onEscapeKeyDown`      | `event => void`                                                              | —       | Intercept Escape key                                                     |

### DialogBody

Optional wrapper for long content. Header and footer stay pinned; only the body scrolls.

| Prop        | Type     | Description            |
| ----------- | -------- | ---------------------- |
| `className` | `string` | Additional CSS classes |

### DialogTrigger

| Prop      | Type      | Description                                        |
| --------- | --------- | -------------------------------------------------- |
| `asChild` | `boolean` | Renders as the child element (use with `<Button>`) |

---

## Examples

### Basic Create Form Dialog

```tsx
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
  Button,
  Input,
  Label,
} from 'xertica-ui/ui';

<Dialog>
  <DialogTrigger asChild>
    <Button>
      <Plus className="size-4 mr-2" /> New Member
    </Button>
  </DialogTrigger>
  <DialogContent size="md">
    <DialogHeader>
      <DialogTitle>Add Team Member</DialogTitle>
      <DialogDescription>Enter the new member's details below.</DialogDescription>
    </DialogHeader>
    <div className="grid gap-4 py-2">
      <div className="grid gap-2">
        <Label htmlFor="name">Full Name</Label>
        <Input id="name" placeholder="John Doe" />
      </div>
      <div className="grid gap-2">
        <Label htmlFor="email">Email</Label>
        <Input id="email" type="email" placeholder="john@example.com" />
      </div>
    </div>
    <DialogFooter>
      <Button type="submit">Save</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>;
```

### Long Content with Pinned Header/Footer

Use `DialogBody` to keep header and footer visible while content scrolls.

```tsx
import {
  Dialog,
  DialogBody,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
  Button,
} from 'xertica-ui/ui';

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">Terms of Service</Button>
  </DialogTrigger>
  <DialogContent size="md">
    <DialogHeader>
      <DialogTitle>Terms of Service</DialogTitle>
    </DialogHeader>
    <DialogBody className="py-2">{/* long scrollable content */}</DialogBody>
    <DialogFooter>
      <Button variant="outline">Decline</Button>
      <Button>Accept</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>;
```

### Controlled Dialog

```tsx
const [open, setOpen] = useState(false);

<Dialog open={open} onOpenChange={setOpen}>
  <DialogTrigger asChild>
    <Button>Open</Button>
  </DialogTrigger>
  <DialogContent size="lg">
    <DialogHeader>
      <DialogTitle>Edit Record</DialogTitle>
    </DialogHeader>
    {/* Form content */}
    <DialogFooter>
      <Button variant="ghost" onClick={() => setOpen(false)}>
        Cancel
      </Button>
      <Button onClick={handleSave}>Save</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>;
```

---

## AI Rules

- Always use `<DialogTrigger asChild>` wrapping a `<Button>` — never render a raw `<button>` as the trigger.
- `DialogTitle` is **required** — omitting it triggers an accessibility error.
- Use the `size` prop to control width — do not override with `className="max-w-..."`.
- For long scrollable content, wrap it in `<DialogBody>` to keep the header and footer pinned.
- For irreversible actions (delete, revoke, reset), use `<AlertDialog>` instead.
- When using with react-hook-form, place `<form onSubmit={...}>` inside `<DialogContent>` and the submit button in `<DialogFooter>`.

---

## Related Components

- [`AlertDialog`](./alert-dialog.md) — For destructive confirmation dialogs
- [`Sheet`](./sheet.md) — For side-panel forms (wider than Dialog)
- [`Drawer`](./drawer.md) — For mobile bottom panels
- [`Form`](./form.md) — For validated forms inside Dialog
