# Popover

- Page: <https://kznlabs.github.io/labsUI/components/popover>

## Popover (`popover`, component)

Non-modal panel anchored to a Button for filters, pickers and quick edits. Focus moves in, Esc returns it, outside clicks close; Selects and menus opened inside don't count as outside.

- Install: `npx @kznlabs/labsui add popover`
- Docs: <https://kznlabs.github.io/labsUI/components/popover>
- Brings: button, button-variants, platform, use-anchor, use-controllable-state, use-dismiss, utils
- npm: clsx@^2.1.1, lucide-react@1.63.0, motion@14.7.1, tailwind-merge@^3.7.0

### API

- `<Popover>`: Non-modal panel anchored to a button: filters, pickers, quick edits. Controlled or uncontrolled.
  - `children: ReactNode`: `PopoverTrigger` and `PopoverContent`.
  - `defaultOpen?: boolean` = `false`: Open at first render (uncontrolled).
  - `onOpenChange?: (open: boolean) => void`: Called on the trigger, Esc or an outside click.
  - `open?: boolean`: Controlled state; pair with `onOpenChange`.
- `<PopoverTrigger>` (+ Button props)
  - `children?: ReactNode`: Label; its width is reserved so loading and success never resize the button.
  - `confirmLabel?: ReactNode`: Two-step action: first click swaps the label to this, second click runs `onClick`.
  - `confirmTimeout?: number`: Ms before an armed confirm step resets. Also resets on blur or Esc.
  - `loading?: boolean`: Disables the button and shows a spinner before the label.
  - `loadingLabel?: ReactNode`: Label shown while loading, with the spinner. Defaults to `children`.
  - `size?: "default" | "sm" | "lg" | "icon"`: Height and padding; "icon" is square, so give it an `aria-label`.
  - `status?: ButtonStatus`: In-place feedback: `loading` spins, `success` swaps the label to `successLabel`.
  - `successLabel?: ReactNode`: Text shown on `status="success"`, with a check icon. Defaults to "Done".
  - `swap?: SwapDirection`: Where the old label slides out to on a swap. Default "left".
  - `variant?: "default" | "secondary" | "outline" | "ghost" | "destructive"`: Fill and emphasis: one primary action per view, `destructive` for irreversible ones.
- `<PopoverContent>`: Focus moves in on open. Esc or an outside click closes it; Esc returns focus to the trigger.
Not a focus trap: Tab past the end closes it and moves on, like any non-modal popup.
  - `children: ReactNode`: Panel content.
  - `align?: "start" | "center" | "end"` = `"center"`: Alignment with the trigger.
  - `side?: "top" | "bottom"` = `"bottom"`: Preferred side; flips when there is no room.

### Usage

```tsx
<Popover><PopoverTrigger variant="outline">Filters</PopoverTrigger><PopoverContent align="start">…</PopoverContent></Popover>
```

### Example: clip-filters.tsx

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

export function ClipFilters() {
  return (
    <Popover>
      <PopoverTrigger variant="outline">Filters</PopoverTrigger>
      <PopoverContent align="start" className="grid gap-3">
        <p className="font-medium text-sm">Filter clips</p>
        <Button size="sm">Apply</Button>
      </PopoverContent>
    </Popover>
  );
}
```
