Popover

A floating panel anchored to a trigger element. Click to open, click-outside or ESC to dismiss. Use for contextual actions, mini-forms, or rich inline info that doesn't warrant a full dialog. Built on @base-ui/react/popover.

Anatomy

PopoverContent is a floating panel with a default width of w-72. It accepts side, align, and sideOffset for positioning. Optional helpers PopoverHeader, PopoverTitle, and PopoverDescription provide consistent internal layout.

side="bottom" (default)align="center" (default)w-72 default width

Positioning

The sideprop controls which side of the trigger the panel appears on. The popover auto-flips if there isn't enough space in the preferred direction.

side="top"
side="right"
side="bottom"
side="left"

Alignment

The align prop shifts the panel relative to the trigger along the cross-axis.

align="start"
align="center"
align="end"

Examples

Mini-form

Info panel

Notification config

Design Guidelines

Do

  • Use for contextual forms and inline info. Popovers are anchored — they make sense for editing a specific value or explaining a specific element.
  • Keep content focused. A popover should serve one purpose. If it grows complex, promote it to a Dialog or Sheet.
  • Use sideOffset for visual breathing room. The default of 4px provides a natural separation from the trigger.

Don't

  • Don't use as a dropdown menu. For lists of actions use DropdownMenu — it handles keyboard navigation, roles, and item focus automatically.
  • Don't put too much content inside. If the popover scrolls, it's trying to be a Dialog — use one instead.
  • Don't rely on hover to trigger. Hover-based popovers are inaccessible on touch devices — use HoverCard only for supplemental previews.

Developer Reference

Accessibility

  • role="dialog" — focus moves into the popover on open.
  • ESC key and clicking outside both dismiss the panel.
  • Renders in a portal — visually floats above the page, still in the accessible DOM tree.
  • PopoverHeader, PopoverTitle, PopoverDescription are layout helpers that do not add semantic roles — use them for consistent spacing.

Usage

import {
  Popover,
  PopoverTrigger,
  PopoverContent,
  PopoverHeader,
  PopoverTitle,
  PopoverDescription,
} from "@/components/ui/popover"

// Basic
<Popover>
  <PopoverTrigger asChild>
    <Button>Open</Button>
  </PopoverTrigger>
  <PopoverContent>
    <PopoverHeader>
      <PopoverTitle>Title</PopoverTitle>
      <PopoverDescription>Supporting text.</PopoverDescription>
    </PopoverHeader>
  </PopoverContent>
</Popover>

// Positioning
<PopoverContent side="top" align="start" sideOffset={8}>
  ...
</PopoverContent>

// Custom width
<PopoverContent className="w-96">
  ...
</PopoverContent>

// Controlled
const [open, setOpen] = useState(false)
<Popover open={open} onOpenChange={setOpen}>...</Popover>