---
title: Popover
description: Floating content panel triggered by clicking a child element.
icon: message-lines
---

import { ComponentPreview } from '/snippets/component-preview.mdx'

Popovers display rich content in a floating panel when users click a trigger element. The first child becomes the trigger; all remaining children become the panel content. Unlike [Tooltip](/components/tooltip) and [HoverCard](/components/hover-card), which appear on hover, Popovers require a click and stay open until the user clicks outside — making them ideal for forms, settings, and menus.

## Basic Usage

<ComponentPreview height="340px" json={{"view":{"type":"Popover","title":"Babel Fish Settings","description":"Configure your universal translator.","children":[{"type":"Button","label":"Open popover","variant":"outline","size":"default","disabled":false},{"cssClass":"gap-3","type":"Column","children":[{"type":"Label","text":"Source Language"},{"name":"input_15","type":"Input","inputType":"text","placeholder":"Vogon","disabled":false,"readOnly":false,"required":false},{"type":"Label","text":"Target Language"},{"name":"input_16","type":"Input","inputType":"text","placeholder":"Galactic Standard","disabled":false,"readOnly":false,"required":false}]}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Button,
    Column,
    Input,
    Label,
    Popover,
)

with Popover(title="Babel Fish Settings", description="Configure your universal translator."):
    Button("Open popover", variant="outline")
    with Column(gap=3):
        Label("Source Language")
        Input(placeholder="Vogon")
        Label("Target Language")
        Input(placeholder="Galactic Standard")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "type": "Popover",
    "title": "Babel Fish Settings",
    "description": "Configure your universal translator.",
    "children": [
      {
        "type": "Button",
        "label": "Open popover",
        "variant": "outline",
        "size": "default",
        "disabled": false
      },
      {
        "cssClass": "gap-3",
        "type": "Column",
        "children": [
          {"type": "Label", "text": "Source Language"},
          {
            "name": "input_15",
            "type": "Input",
            "inputType": "text",
            "placeholder": "Vogon",
            "disabled": false,
            "readOnly": false,
            "required": false
          },
          {"type": "Label", "text": "Target Language"},
          {
            "name": "input_16",
            "type": "Input",
            "inputType": "text",
            "placeholder": "Galactic Standard",
            "disabled": false,
            "readOnly": false,
            "required": false
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Without Header

Skip the `title` and `description` to render content directly in the panel.

<ComponentPreview height="260px" json={{"view":{"type":"Popover","children":[{"type":"Button","label":"Settings","variant":"outline","size":"default","disabled":false},{"cssClass":"gap-3","type":"Column","children":[{"type":"Label","text":"Improbability Factor"},{"name":"improbability","type":"Slider","min":0.0,"max":100.0,"value":42.0,"disabled":false}]}]},"state":{"improbability":42.0}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQnV0dG9uLAogICAgQ29sdW1uLAogICAgTGFiZWwsCiAgICBQb3BvdmVyLAogICAgU2xpZGVyLAopCgp3aXRoIFBvcG92ZXIoKToKICAgIEJ1dHRvbigiU2V0dGluZ3MiLCB2YXJpYW50PSJvdXRsaW5lIikKICAgIHdpdGggQ29sdW1uKGdhcD0zKToKICAgICAgICBMYWJlbCgiSW1wcm9iYWJpbGl0eSBGYWN0b3IiKQogICAgICAgIFNsaWRlcihtaW49MCwgbWF4PTEwMCwgdmFsdWU9NDIsIG5hbWU9ImltcHJvYmFiaWxpdHkiKQo=">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Button,
    Column,
    Label,
    Popover,
    Slider,
)

with Popover():
    Button("Settings", variant="outline")
    with Column(gap=3):
        Label("Improbability Factor")
        Slider(min=0, max=100, value=42, name="improbability")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "type": "Popover",
    "children": [
      {
        "type": "Button",
        "label": "Settings",
        "variant": "outline",
        "size": "default",
        "disabled": false
      },
      {
        "cssClass": "gap-3",
        "type": "Column",
        "children": [
          {"type": "Label", "text": "Improbability Factor"},
          {
            "name": "improbability",
            "type": "Slider",
            "min": 0.0,
            "max": 100.0,
            "value": 42.0,
            "disabled": false
          }
        ]
      }
    ]
  },
  "state": {"improbability": 42.0}
}
```
</CodeGroup>
</ComponentPreview>

## Positioning

Control which side the panel appears on with the `side` prop:

```python
from prefab_ui.components import Button, Popover, Text

with Popover(title="Guide Entry", side="right"):
    Button("Hover for info", variant="outline")
    Text("A towel is about the most massively useful thing an interstellar hitchhiker can have.")
```

The renderer auto-adjusts if the popover would overflow the viewport, so the `side` is a preference rather than a hard constraint.

## Inline Confirmation

For lighter-weight confirmations that don't need a full modal overlay, a Popover works well. The same trigger-then-content pattern applies.

<ComponentPreview json={{"view":{"type":"Popover","children":[{"type":"Button","label":"Archive","variant":"outline","size":"default","disabled":false},{"cssClass":"gap-2","type":"Column","children":[{"content":"Archive this item?","type":"Text"},{"type":"Button","label":"Confirm","variant":"default","size":"default","disabled":false,"onClick":[{"action":"toolCall","tool":"archive_item","arguments":{"id":"{{ item_id }}"}},{"action":"closeOverlay"}]}]}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Button, Column, Popover, Text
from prefab_ui.actions import CloseOverlay
from prefab_ui.actions.mcp import CallTool
from prefab_ui.rx import Rx

item_id = Rx("item_id")

with Popover():
    Button("Archive", variant="outline")
    with Column(gap=2):
        Text("Archive this item?")
        Button(
            "Confirm",
            on_click=[
                CallTool("archive_item", arguments={"id": item_id}),
                CloseOverlay(),
            ],
        )
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "type": "Popover",
    "children": [
      {
        "type": "Button",
        "label": "Archive",
        "variant": "outline",
        "size": "default",
        "disabled": false
      },
      {
        "cssClass": "gap-2",
        "type": "Column",
        "children": [
          {"content": "Archive this item?", "type": "Text"},
          {
            "type": "Button",
            "label": "Confirm",
            "variant": "default",
            "size": "default",
            "disabled": false,
            "onClick": [
              {
                "action": "toolCall",
                "tool": "archive_item",
                "arguments": {"id": "{{ item_id }}"}
              },
              {"action": "closeOverlay"}
            ]
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## API Reference

<Card icon="code" title="Popover Parameters">
<ParamField body="title" type="str | None" default="None">
  Optional header title for the popover panel.
</ParamField>

<ParamField body="description" type="str | None" default="None">
  Optional description below the title.
</ParamField>

<ParamField body="side" type="str | None" default="None">
  Preferred side to show the popover: `"top"`, `"right"`, `"bottom"`, `"left"`.
</ParamField>

<ParamField body="css_class" type="str | None" default="None">
  Additional Tailwind CSS classes.
</ParamField>
</Card>

## Protocol Reference

```json Popover
{
  "type": "Popover",
  "children?": "[Component]",
  "let?": "object",
  "title?": "string",
  "description?": "string",
  "side?": "top | right | bottom | left",
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Popover](/protocol/popover).
