# Overlay Components

> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.

## Dialog

Centered modal panel (`@nurix/components/compound/dialog`); Base UI owns focus, scroll lock and dismissal.

**Sub-components:** `Dialog.Trigger`, `Dialog.MorphTrigger`, `Dialog.Popup`, `Dialog.Header`, `Dialog.Body`, `Dialog.Footer`, `Dialog.Title`, `Dialog.Description`, `Dialog.Close`; also `dialogPopupVariants`

**Root props:** `intent` [neutral|info|success|warning|danger] (`danger` renders an alert dialog), `dismissible` (default true; false when `intent="danger"`; governs Escape, outside press and focus-out only, `Dialog.Close` always closes), `labels` `{ close, title }`, `modal`

**Popup props:** `size` [xs|sm|default|lg|full] (`full` fills the viewport with a thin gap), `title`, `description`, `icon` (render a built-in header), `hasCloseButton` (defaults to the resolved dismissibility, so a danger dialog draws no ✕), `hasDivider`

**Header/Footer props:** `hasDivider` **Body:** the one scroll region; the popup caps at the viewport, so the footer stays in view

```tsx
<Dialog>
  <Dialog.Trigger render={<Button />}>Edit profile</Dialog.Trigger>
  <Dialog.Popup size="lg">
    <Dialog.Header hasDivider>
      <Dialog.Title>Edit Profile</Dialog.Title>
    </Dialog.Header>
    <Dialog.Body>
      <Input value={name} onValueChange={setName} />
    </Dialog.Body>
    <Dialog.Footer hasDivider>
      <Dialog.Close render={<Button variant="outline" />}>Cancel</Dialog.Close>
      <Button onClick={handleSave}>Save</Button>
    </Dialog.Footer>
  </Dialog.Popup>
</Dialog>
```

Destructive confirmation is `<Dialog intent="danger">` with no separate AlertDialog. An untitled popup is named from `labels.title` ("Dialog") unless it carries `aria-label`; pass `title` or `aria-label`, never a second `Dialog.Title` beside the placeholder.

## Sheet

Edge-pinned modal panel (`@nurix/components/block/sheet`) with a header/body/footer layout.

**Sub-components:** `Sheet.Trigger`, `Sheet.Popup`, `Sheet.Header`, `Sheet.Body`, `Sheet.Footer`, `Sheet.Title`, `Sheet.Description`, `Sheet.Close`; also `sheetSizeVariants`

**Root props:** `intent` [neutral|info|success|warning|danger] (`danger` renders an alert dialog), `dismissible` (default true; false when `intent="danger"`), `labels` `{ close, title }`, `modal` (`false` or `"trap-focus"` draws no scrim)

**Popup props:** `side` [start|end|top|bottom] (default `end`; logical, so `end` opens from the left in RTL), `size` [xs|sm|default|lg|full] (width of a start/end sheet, height cap of a top/bottom one), `hasCloseButton` (defaults to the resolved dismissibility), `overlayClassName`

**Header/Footer props:** `hasDivider` **Body props:** `className` styles the padded content box; `className="p-0"` drops the inset

```tsx
<Sheet>
  <Sheet.Trigger render={<Button />}>Open</Sheet.Trigger>
  <Sheet.Popup side="end" size="lg">
    <Sheet.Header hasDivider>
      <Sheet.Title>Settings</Sheet.Title>
    </Sheet.Header>
    <Sheet.Body>
      <Input value={name} onValueChange={setName} />
    </Sheet.Body>
    <Sheet.Footer hasDivider>
      <Button onClick={handleSave}>Save</Button>
    </Sheet.Footer>
  </Sheet.Popup>
</Sheet>
```

A bottom drawer is `side="bottom"`. Omitting `Sheet.Title` names every sheet "Sheet" (`labels.title`); give each one a title. An in-flow docked region that reflows its sibling instead of overlaying it is `SidePanel` (`block/side-panel`, see [layout](layout.md)).

## Morphing overlay

`Dialog.MorphTrigger` and `Popover.MorphTrigger` grow the popup out of the trigger's own box (shared layout on the slow motion step) instead of the plain open transition. Use one in place of the family's `Trigger`; it takes no `render` (style it with `className`), and under reduced motion the popup opens on the plain transition.

## Other Overlays

Namespaced compounds over Base UI: each `Trigger` composes your element through `render` (no `asChild`), each floating part is a `Popup` that portals itself, and there is no `Portal` part.

- `Command` (`compound/command`) — `.Input`, `.List`, `.Empty`, `.Loading`, `.Error`, `.Group`, `.Item`, `.Separator`, `.Shortcut`, `.Results` (`data`, `renderItem`), `.Footer`; a dialog palette is `.Dialog` + `.Trigger` (children are its text; `shortcut`, `size` [default|sm]) + `.Popup`; the query lives on the root (`searchValue`/`onSearchValueChange`), plus `loading`, `error`, `filter` (`null` turns it off); items fire `onClick`, never `onSelect`; fetch with `useSearchSource` (`hooks/use-search-source`)
- `ContextMenu` (`compound/context-menu`) — right-click or long-press on `.Trigger`; `.Popup` requires `aria-label` or `aria-labelledby`; the same item parts as `DropdownMenu`
- `DropdownMenu` (`compound/dropdown-menu`) — `.Trigger`, `.Popup`, `.Item`, `.LinkItem` (`href`), `.CheckboxItem`, `.RadioGroup`/`.RadioItem`, `.Label`, `.Separator`, `.Group`, `.Shortcut`, `.Sub`/`.SubTrigger`/`.SubPopup`; items fire `onClick` (`closeOnClick={false}` keeps it open), `intent="danger"`, `isInset`; popups take `side`, `align`, `sideOffset`, `alignOffset`, `collisionPadding`, `anchor`
- `Popover` (`element/popover`) — `.Trigger`, `.MorphTrigger`, `.Popup` (default `side="bottom"`, `align="center"`, `sideOffset={4}`), `.Arrow`, `.Title`, `.Description`, `.Close`; a hover card is `<Popover.Trigger openOnHover delay closeDelay>`
- `Tooltip` (`element/tooltip`) — `.Trigger`, `.Popup` (`side`, `sideOffset` default 4, `align`), `.Arrow` (none by default), `.Provider` (one per toolbar, shared `delay`); `intent` and `disabled` on the root; an icon-only trigger still needs its own `aria-label`
- `ActionBar` (`compound/action-bar`) — hover-revealed icon toolbar anchored to the root's other children: `.Bar` (a direct child of the root; `variant` [floating|bare]), `.Action` (`label`, `pressed`); root `side` [top|bottom|start|end] (default bottom), `align` (default end), `offset`, `orientation`, `reveal` [hover|always|hidden]; also `actionBarVariants`
- `SpeedDial` (`compound/speed-dial`) — `.Trigger` + `.Action` (`label` is its name and tooltip; `onClick`); `side` [start|end] (default start); renders inline, so the host positions it; `event.preventDefault()` in an action's `onClick` keeps it open
