Skip to content

Overlays & navigation

Popover

A popover is a small non-modal panel anchored to a button: share settings, a quick form, an explanation. It renders in the browser's top layer with the native Popover API, so it is never clipped by a scrolling container and sits above dialogs, and it positions itself on any side of the trigger without a positioning library, flipping and staying inside the viewport.

On this page

Usage

components/ui/popover.tsx
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; <Popover align="end">  <PopoverTrigger>    <Button>Share</Button>  </PopoverTrigger>  <PopoverContent aria-label="Share invoice">…</PopoverContent></Popover>

Examples

Share panel

Any element works as the trigger; it receives aria-expanded and aria-controls. Content is plain JSX.

Placement

`placement` picks the side (start and end follow the reading direction) and `align` the edge. Popovers flip when the preferred side has no room.

Quick form

Focus moves to the first field on open. PopoverClose wraps buttons that should close the panel and return focus to the trigger.

Explanation

For help text that contains more than a few words, or that people need to read slowly, use a popover rather than a tooltip.

Net revenue€48,210

Props

Popover

  • placement"top" | "bottom" | "start" | "end"default: "bottom"Preferred side of the trigger. Flips when there is not enough room.
  • align"start" | "center" | "end"default: "center"Which edge of the trigger the panel lines up with.
  • offsetnumberdefault: 8Gap between trigger and panel, in pixels.
  • openbooleandefault: —Controlled open state. Pair with onOpenChange.
  • defaultOpenbooleandefault: falseInitial state when uncontrolled.
  • onOpenChange(open: boolean) => voiddefault: —Called when the popover opens or closes.

PopoverTrigger, PopoverContent, PopoverClose

  • PopoverTrigger{ children, className }default: —Pass your own button element (it gets aria-haspopup, aria-expanded, aria-controls and the click handler) or plain text for a default button.
  • PopoverContent{ aria-label, padded?, className, children }default: —The panel: 288px wide, 16px padding (padded={false} removes it). Set a width with className.
  • PopoverClose{ children: ReactElement }default: —Wraps a button so a click closes the popover and focuses the trigger again.

Helpers

  • useFloating(open, anchorRef, panelRef, { placement, align, offset })default: —Shows a popover="manual" element and keeps it anchored. Used by Tooltip and Dropdown menu.
  • computePosition(rect, w, h, placement, align, offset, rtl?)default: —The positioning math on its own: returns top, left and the final side.

Accessibility

  • The panel has role="dialog" and needs a name: pass aria-label, or aria-labelledby pointing at a heading inside it.
  • The trigger gets aria-haspopup="dialog", aria-expanded and aria-controls, so screen readers announce that it opens a panel and whether it is open.
  • On open, focus moves to the first focusable element in the panel; Tab continues from there in reading order.
  • Escape closes the popover and returns focus to the trigger. A click outside or moving focus out of the panel also closes it.
  • The popover is non-modal: the rest of the page stays usable. Use a Dialog when the user must finish or cancel first.

Suggested