---
title: Popover
description: Displays rich content in a portal, triggered by a button.
icon: message-circle
author:
  name: imskyleen
  url: https://github.com/imskyleen
search:
  keywords: [popup, floating panel]
related:
  - /tooltip
  - /hover-card
  - /dropdown-menu
mode: wide
---

<PoweredBy
  packages={[
    { name: 'Base UI', url: 'https://base-ui.com/react/components/popover' },
    { name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/popover' },
  ]}
/>

### Installation

```package-install
npx shadcn@latest add @redpanda/popover
```

<ComponentPreview
  name="popover-demo"
  description="Default popover opened by a trigger button with rich form content."
/>

### Positioning

<ComponentPreview
  name="popover-side-demo"
  description="Place content on any side (top / right / bottom / left) via the `side` prop."
/>

### Controlled

<ComponentPreview
  name="popover-controlled-demo"
  description="Drive `open` from parent state with `onOpenChange` and toggle it from outside the trigger."
/>

## When to use

The Popover component displays rich content in a positioned overlay triggered by user interaction. Use this decision tree to determine when it's appropriate:

```mermaid
graph TD;
    A[❓ Need contextual content?] --> B{Triggered by user action?};
    A --> C[ℹ️ Use always-visible content];
    B --> D{Rich content needed?};
    B --> E{Simple tooltip sufficient?};
    D --> F[✅ Use Popover];
    E --> G[✅ Use Tooltip];
    E --> H{Form or interactive content?};
    H --> I[✅ Use Popover];
    H --> J{Modal behavior needed?};
    J --> K[✅ Use Dialog];
    J --> L[✅ Use Popover];

    classDef recommended fill:#4ade80,stroke:#22c55e,stroke-width:2px,color:#000;
    classDef discouraged fill:#fbbf24,stroke:#f59e0b,stroke-width:2px,color:#000;
    classDef decision fill:#60a5fa,stroke:#3b82f6,stroke-width:2px,color:#fff;
    classDef neutral fill:#9ca3af,stroke:#6b7280,stroke-width:2px,color:#fff;

    class F,G,I,K,L recommended;
    class A,B,D,E,H,J decision;
    class C neutral;
```

## Usage

```tsx
<Popover>
  <PopoverTrigger>Open Popover</PopoverTrigger>
  <PopoverContent>Popover Content</PopoverContent>
</Popover>
```

## Examples

### Date Picker Example

<ComponentPreview name="popover-datepicker-demo" />

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://base-ui.com/react/components/popover" text="Docs" />
  <ExternalLink href="https://base-ui.com/react/components/popover#api-reference" text="API Reference" />
</div>

### Content padding

Use `PopoverContent padding="none"` for a calendar or another component that owns
its own inset. `padding="sm"` supplies 8 pixels and the default `padding="md"`
supplies 16 pixels. Keep placement and width classes on the popup; do not override
its padding with utilities.

## Keyboard interactions

| Key                                   | Action                                                      |
| ------------------------------------- | ----------------------------------------------------------- |
| `Enter` / `Space` on `PopoverTrigger` | Toggles the popover open/closed.                            |
| `Tab` / `Shift+Tab`                   | Cycles focus between focusable elements inside the popover. |
| `Escape`                              | Closes the popover and restores focus to the trigger.       |
| Click outside `PopoverContent`        | Closes the popover.                                         |

## Accessibility

- `PopoverTrigger` exposes `aria-expanded` / `aria-controls` for the screen-reader state of the popover.
- `PopoverContent` is focusable and traps focus while open — pressing `Tab` past the last focusable control wraps back
  to the first.
- The trigger must be a real button (or another interactive element via the `render` prop). Static `<div>` triggers lose focus
  behaviour.
- `onOpenChange` uses Base UI's native `(open, eventDetails) => void` signature.

## Controlled vs uncontrolled

Uncontrolled — the popover owns open state:

```tsx lineNumbers
<Popover onOpenChange={(open) => console.log('open:', open)}>
  <PopoverTrigger>Open</PopoverTrigger>
  <PopoverContent>{/* ... */}</PopoverContent>
</Popover>
```

Controlled — drive `open` from parent state (e.g. to open the popover programmatically or close it after a form
submission):

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

<Popover open={open} onOpenChange={setOpen}>
  <PopoverTrigger
    render={
      <Button onClick={() => undefined} variant="outline">
        Open
      </Button>
    }
  />
  <PopoverContent>
    <Button onClick={() => setOpen(false)}>Done</Button>
  </PopoverContent>
</Popover>;
```

## Credits

- We use [Base UI](https://base-ui.com/react/components/popover) for the popover component.
- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/popover) for the popover style.
