# Popover

A small panel anchored to the button that opens it, for content the user acts in without leaving the page: a short form, filters, a share link. It sits on the raised surface with a border and a medium shadow, and closes on Escape, an outside press or its trigger.

## Usage

### When to use

- A few controls next to the button that opens them: a share link, filters, a quick setting.
- Content the user acts in without leaving the page, which closes on Escape or a press outside.

### When not to use

- A list of actions. Use DropdownMenu.
- A hint on hover or focus, with no controls. Use Tooltip.
- A long form, or input the user must not lose on a press outside. Use Dialog.

## Variants

### side

Set on PopoverContent. The side of the trigger it opens on. It flips when there is no room.

Values: `top`, `right`, `bottom`, `left`. Default: `bottom`.

### align

Set on PopoverContent. How it lines up with the trigger along that side. Use start or end when the trigger sits near an edge.

Values: `start`, `center`, `end`. Default: `center`.

## Examples

### Share link

```tsx
<Popover>
  <PopoverTrigger asChild>
    <Button variant="secondary">Share</Button>
  </PopoverTrigger>
  <PopoverContent aria-labelledby="share-heading" className="flex flex-col gap-md">
    <p id="share-heading" className="text-md font-medium">Share this project</p>
    <Field>
      <FieldLabel>Link</FieldLabel>
      <FieldControl>
        <Input readOnly defaultValue="https://example.com/p/42" />
      </FieldControl>
    </Field>
    <PopoverClose asChild>
      <Button>Done</Button>
    </PopoverClose>
  </PopoverContent>
</Popover>
```

### Next to an edge

align end keeps the panel on screen when the trigger sits at the right of a toolbar.

```tsx
<Popover>
  <PopoverTrigger asChild>
    <Button variant="secondary" iconOnly aria-label="Filters">
      <IconList size={16} />
    </Button>
  </PopoverTrigger>
  <PopoverContent align="end" aria-label="Filters" className="flex flex-col gap-md">
    <Checkbox label="Only my projects" />
    <Checkbox label="Show archived" />
  </PopoverContent>
</Popover>
```

## Do and don't

### Do

- Keep it short: a few controls, a link to copy, a set of filters.
- Give the panel a heading, or an aria-label when it has none.
- Apply changes at once, or close it with a PopoverClose button such as Done.

### Don't

- Don't put a list of actions in it; use DropdownMenu.
- Don't use it for a long form or anything the user must not lose on an outside press; use Dialog.
- Don't open it on hover; use Tooltip for a hint.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `open` | `boolean` |  |  | Set on Popover. Whether it is open, when you control it. Pair it with onOpenChange. |
| `defaultOpen` | `boolean` |  | `false` | Set on Popover. Opens it on first render, when you don't control it. |
| `onOpenChange` | `function` |  |  | Set on Popover. Called with true or false when it opens or closes (trigger, Escape, an outside press, PopoverClose). |
| `modal` | `boolean` |  | `false` | Set on Popover. true keeps focus inside and hides the rest of the page from assistive tech until it closes. Leave it false for a panel the user works next to. |
| `side` | `enum` | `top`, `right`, `bottom`, `left` | `bottom` | Set on PopoverContent. The side of the trigger it opens on. It flips when there is no room. |
| `align` | `enum` | `start`, `center`, `end` | `center` | Set on PopoverContent. How it lines up with the trigger along that side. Use start or end when the trigger sits near an edge. |
| `sideOffset` | `number` |  | `4` | Set on PopoverContent. Space between the trigger and the panel, in px. 4 is spacing-xs. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `trigger` | yes | PopoverTrigger with asChild around a Button. |
| `content` | yes | PopoverContent with a heading or an aria-label, and the controls. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | Popover. Holds the open state; renders nothing itself. |
| `trigger` | PopoverTrigger: the button that opens it, usually a Button with asChild. |
| `content` | PopoverContent: the panel. Raised fill, border, radius-container, shadow-med, px-lg py-md, 288px wide and never wider than the screen minus spacing-sm on each side. |
| `anchor` | PopoverAnchor (optional): another element to position the panel against. |
| `close` | PopoverClose (optional): a button inside that closes it, such as Done. |

## Accessibility

Role: `dialog`

| Keys | Action |
| --- | --- |
| `Space, Enter` | On the trigger: opens or closes the popover. Focus moves to the first focusable element inside, or to the panel. |
| `Tab` | Moves through the controls inside. With modal, focus stays inside; otherwise it can leave, and the popover stays open. |
| `Escape` | Closes the popover and returns focus to the trigger. |

- The trigger gets aria-expanded and aria-controls, and the panel is a dialog. Name it with aria-label or aria-labelledby when it has no heading.
- An outside press closes it. Put anything the user must not lose (unsaved input) in a Dialog instead.
- Not for a list of actions: that is a DropdownMenu, which has menu semantics and arrow keys.
- Not for a hint on hover: that is a Tooltip, which holds no controls.

## Install

```bash
npx shadcn add https://werewolf-ui.vercel.app/r/popover.json
```

This also adds `styles/werewolf.css`, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after `@import "tailwindcss"`, with a path relative to that CSS file (from `app/globals.css` it is `@import "../styles/werewolf.css"`).
