Gesso
Overlays

Popover

A raised panel anchored to a trigger. Click to open, Escape or a click outside to close.

A small panel that opens beside the control that asked for it, for a few filters, a short form, or a picker that does not need a whole screen. It sits on the Radix popover, which positions it against the trigger, flips it when it would run off the window, and leaves the rest of the page usable. Combobox and Date picker are built on it.

Usage

import { Button } from '@/components/ui/button';
import {
  Popover,
  PopoverContent,
  PopoverDescription,
  PopoverHeader,
  PopoverTitle,
  PopoverTrigger,
} from '@/components/ui/popover';

<Popover>
  <PopoverTrigger asChild>
    <Button>Filters</Button>
  </PopoverTrigger>
  <PopoverContent>
    <PopoverHeader>
      <PopoverTitle>Filters</PopoverTitle>
      <PopoverDescription>Applied to this view only.</PopoverDescription>
    </PopoverHeader>
  </PopoverContent>
</Popover>

PopoverContent is 288px wide with 16px of padding and a 10px gap between its children, on the raised surface with a light ring and a shadow. Pass className to change the width, like w-56. PopoverHeader, PopoverTitle, and PopoverDescription are optional layout slots, and PopoverClose closes the panel from inside it.

Where it opens

side picks the edge of the trigger it opens from, align picks start, center, or end along that edge, and sideOffset sets the gap, 4px by default. The panel flips to the other side when there is no room, as on the Radix popover, and collisionPadding keeps it off the window edge.

To open the panel against something other than the trigger, put PopoverAnchor around that element. The trigger still opens it, and the panel positions to the anchor.

The popover is not modal by default, so the page behind it stays scrollable and clickable. Clicking elsewhere closes it, and so does Escape or moving focus out of it, and a click on the trigger toggles it. modal on Popover makes it hold focus the way a dialog does: focus cannot be moved out of the panel, the page behind it is hidden from assistive tech and cannot scroll, and a click outside closes it without reaching the page. Reach for modal when the panel is a task the user should finish, and for a Dialog when it deserves a scrim, which a popover never has.

Motion

The panel fades in and out and does not slide or scale, so it does not fight the Radix positioning, which moves it with a transform. Under reduced motion it appears and disappears without animating.

Props

Popover, PopoverTrigger, PopoverAnchor, and PopoverClose are the Radix popover parts, with open, defaultOpen, onOpenChange, and modal as on the Radix popover. PopoverContent takes the Radix content props, with two defaults changed.

PropTypeDefaultWhat it does
align"start" | "center" | "end""center"Where the panel lines up along the trigger's edge.
sideOffsetnumber4The gap in pixels between the trigger and the panel.

side, alignOffset, collisionPadding, onOpenAutoFocus, onCloseAutoFocus, and the other Radix content props pass through.

Accessibility

  • The trigger is a native button, so Enter and Space open it. It carries aria-haspopup="dialog", aria-expanded, and, while open, aria-controls pointing at the panel.
  • The panel has role="dialog". PopoverTitle and PopoverDescription are a plain heading and paragraph and are not wired to it, so the panel has no accessible name until you set aria-label or aria-labelledby on PopoverContent.
  • Focus moves into the panel on open, to the first focusable element in it, and goes back to the trigger on close, unless the user closed it by clicking elsewhere, in which case focus stays where the click put it.
  • Escape closes it. Tab and Shift+Tab loop within the panel, from the last element to the first, so the keyboard does not walk out of it. That is the only trapping a popover does by default: it does not hide the page or lock scrolling unless modal is on, and a click or a programmatic focus outside closes it.
  • The panel carries a transparent outline that the system paints in forced colors, so its edge stays visible in Windows high contrast. The ring and shadow are removed there.
  • Nothing in the popover sets a touch target size, so the controls you put in it need their own.
  • Under reduced motion it opens and closes without the fade.

When to use something else

  • Hover card for a preview that opens on hover and holds nothing the user has to act on. A popover opens on click and its content can be interactive.
  • Tooltip for a one-line label on an icon or a control. A tooltip names something and is never interactive.
  • Dropdown menu for a list of actions, since it brings arrow-key navigation, typeahead, and a menu role that a popover does not.
  • Dialog or Sheet when the content needs the user's full attention or more room than a panel beside a control can give.

Install

shadcn add @gesso/popover

On this page