# Popover

Popover is a neobrutalist React component from Cruise UI. A small panel tied to a button: a title, content and actions; a bottom sheet on phones for longer content.

Install (with the @cruiseui registry in components.json, see Installation):

```bash
npx shadcn@latest add @cruiseui/popover
```

Import: `import { CruisePopover } from "@/components/cruise/popover";`

## When to use

Extra detail or a quick action next to what it's about: how a fee is worked out, a share menu, a short form.

## When not to

Hints on hover (use a Tooltip). Anything that needs the whole screen's attention (use a Modal).

## Example (React)

```tsx
"use client";

import { Info } from "lucide-react";
import { CruiseButton } from "@/components/cruise/button";
import { CruisePopover } from "@/components/cruise/popover";

export default function PopoverExample() {
  return (
    <div className="flex flex-wrap gap-4">
      <CruisePopover
        title="Delivery fee"
        trigger={
          <CruiseButton variant="secondary">
            <Info aria-hidden="true" />
            How is this worked out?
          </CruiseButton>
        }
        actions={(close) => (
          <CruiseButton variant="secondary" onClick={close}>
            Got it
          </CruiseButton>
        )}
      >
        ₦1,500 within Lagos Island, ₦2,500 to the Mainland. Free on orders over ₦20,000.
      </CruisePopover>
      <CruisePopover sheet title="Order details" trigger={<CruiseButton variant="secondary">Order #1042</CruiseButton>}>
        Classic Celebration Cake × 1, Cupcake Box (6) × 2. Paid by card on 12 October. Out for delivery.
      </CruisePopover>
    </div>
  );
}
```

## HTML

Needs theme.css (https://cruiseui.dev/theme.css).

```html
<button type="button" class="brutal btn btn-secondary" aria-expanded="false" aria-controls="fee-pop" popovertarget="fee-pop">How is this worked out?</button>
<div class="popover" id="fee-pop" popover role="dialog" aria-labelledby="fee-pop-title">
  <p class="popover-title" id="fee-pop-title">Delivery fee</p>
  <div class="popover-body">₦1,500 within Lagos Island, ₦2,500 to the Mainland. Free on orders over ₦20,000.</div>
  <div class="popover-actions"><button type="button" class="brutal btn btn-secondary" popovertarget="fee-pop" popovertargetaction="hide">Got it</button></div>
</div>
<!-- The HTML popover attribute gives Esc / outside-click closing; place it under its trigger with CSS anchor positioning or a little JS. -->
```

## Props: CruisePopover

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `trigger` | `ReactElement<unknown, string \| JSXElementConstructor<any>>` | — | The button that opens it (gets aria-expanded / aria-controls). |
| `title?` | `ReactNode` | — | — |
| `children` | `ReactNode` | — | — |
| `actions?` | `ReactNode \| ((close: () => void) => ReactNode)` | — | Buttons under the content; a function gets `close`. |
| `arrow?` | `boolean` | `true` | — |
| `side?` | `"left" \| "right" \| "top" \| "bottom"` | `"bottom"` | — |
| `align?` | `"center" \| "start" \| "end"` | `"center"` | — |
| `sheet?` | `boolean` | `false` | Below 640px, open as a bottom sheet instead (for long content). |
| `open?` | `boolean` | — | — |
| `onOpenChange?` | `((open: boolean) => void)` | — | — |
| `popupClassName?` | `string` | — | — |

## Accessibility

- Opens on click; Esc and a click outside close it.
- Focus moves into the popover and back to the trigger when it closes.
- The trigger has aria-expanded and aria-controls; the title names the popover.
