# Popover

A floating panel anchored to a trigger — for non-modal overlays, forms, and contextual detail.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available by appending `.md` to any URL or sending an `Accept: text/markdown` header. An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md).





<ComponentThemeTabs>
  <ThemeTab name="mint">
    <PreviewWithCode name="popover">
      <PopoverDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="berries">
    <PreviewWithCode name="popover">
      <PopoverDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="citrine">
    <PreviewWithCode name="popover">
      <PopoverDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="cinnamon">
    <PreviewWithCode name="popover">
      <PopoverDemo />
    </PreviewWithCode>
  </ThemeTab>
</ComponentThemeTabs>

## Placement [#placement]

Control placement with `side` and `align` on `PopoverContent`. Defaults to `side="bottom" align="center"`.

```tsx
<PopoverContent side="right" align="start">
  ...
</PopoverContent>
```

## Controlled [#controlled]

Manage open state externally with `open` and `onOpenChange`.

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

<Popover open={open} onOpenChange={setOpen}>
  <PopoverTrigger asChild>
    <Button onClick={() => setOpen(true)}>Open</Button>
  </PopoverTrigger>
  <PopoverContent>
    <Button variant="ghost" onClick={() => setOpen(false)}>Close</Button>
  </PopoverContent>
</Popover>
```

## With sounds [#with-sounds]

Pass `sounds` to play open/close audio feedback (uses `dropdownOpen` / `dropdownClose`).

```tsx
<Popover sounds>
  ...
</Popover>
```

## Custom anchor [#custom-anchor]

Use `PopoverAnchor` when the popover should be positioned relative to a different element than the trigger.

```tsx
<Popover>
  <PopoverAnchor asChild>
    <div className="border rounded-md p-4">Anchor element</div>
  </PopoverAnchor>
  <PopoverTrigger asChild>
    <Button>Open</Button>
  </PopoverTrigger>
  <PopoverContent>Content positioned relative to the anchor.</PopoverContent>
</Popover>
```

## Popover vs Dialog [#popover-vs-dialog]

|             | Popover                                  | Dialog                          |
| ----------- | ---------------------------------------- | ------------------------------- |
| Interaction | Non-modal — background stays interactive | Modal — background blocked      |
| Dismiss     | Click outside or Escape                  | Explicit close button or Escape |
| Use for     | Contextual forms, filters, detail        | Confirmations, focused tasks    |

## Props [#props]

### Popover [#popover]

| Prop           | Type                      | Default | Description                     |
| -------------- | ------------------------- | ------- | ------------------------------- |
| `open`         | `boolean`                 | —       | Controlled open state           |
| `defaultOpen`  | `boolean`                 | `false` | Uncontrolled initial state      |
| `onOpenChange` | `(open: boolean) => void` | —       | Callback when state changes     |
| `sounds`       | `boolean`                 | `false` | Plays open/close audio feedback |

### PopoverContent [#popovercontent]

| Prop         | Type                                     | Default    | Description                                  |
| ------------ | ---------------------------------------- | ---------- | -------------------------------------------- |
| `side`       | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Preferred side                               |
| `align`      | `"start" \| "center" \| "end"`           | `"center"` | Alignment relative to trigger                |
| `sideOffset` | `number`                                 | `4`        | Gap between trigger and panel                |
| `className`  | `string`                                 | —          | Default width is `w-72` — override as needed |

## Usage [#usage]

```tsx
import { Button } from "@/components/ui/button";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";

<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline">Open</Button>
  </PopoverTrigger>
  <PopoverContent>
    <p className="text-sm">Popover content here.</p>
  </PopoverContent>
</Popover>
```

## Specs [#specs]

```md
# Mint — Popover Specs

## Component
- name: popover
- file: registry/mint/popover.tsx
- installs to: components/ui/popover.tsx
- dependencies: radix-ui
- registryDependencies: none

## What is it
A non-modal floating panel anchored to a trigger element, rendered in a Portal
via Radix UI Popover. Use it for contextual forms, filters, and detail overlays
that must not block the rest of the UI. Prefer Dialog when the task requires
full user attention or a modal backdrop.

## Visual identity
Floating surface uses --popover (white in light, dark grey in dark) with a
subtle shadow-md and 0.625rem border radius, giving a clean and contained feel.
Default width is w-72 with p-4 padding — compact but readable.

## Design tokens
--popover: oklch(1 0 0) / oklch(0.269 0 0)           — panel background
--popover-foreground: oklch(0.145 0 0) / oklch(0.985 0 0) — panel text
--border: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%)      — panel border

## Sub-components
- Popover        → Root; accepts sounds prop for open/close audio feedback
- PopoverTrigger → wraps the trigger element; use asChild to forward to a Button
- PopoverContent → floating panel rendered in Portal; default w-72, p-4, sideOffset=4
- PopoverAnchor  → optional alternative positioning anchor, independent of trigger

## States
- data-[state=open]:   fade-in-0 + zoom-in-95 + slide-in-from-{side}-2
- data-[state=closed]: fade-out-0 + zoom-out-95
- data-[side=bottom]:  slides in from top-2
- data-[side=top]:     slides in from bottom-2
- data-[side=left]:    slides in from right-2
- data-[side=right]:   slides in from left-2

## Conventions
- Default placement is side="bottom" align="center" — override via PopoverContent props
- sideOffset defaults to 4px; increase for more visual separation from the trigger
- PopoverContent default width is w-72 — pass className to override
- Use PopoverAnchor when the panel should be positioned relative to a different element than the trigger
- Sub-components expose data-slot="popover", data-slot="popover-trigger", data-slot="popover-content", data-slot="popover-anchor" for CSS targeting
- sounds / haptic: GIN Design exclusive — plays audio (dropdownOpen / dropdownClose) on open and close via useFeedback hook
```

## Installation [#installation]

<CommandBox componentName="popover" className="mt-2" />
