Join our Discord Community

Popover

Displays rich content in a portal, triggered by a button. Built for React applications with Next.js integration and TypeScript support.

Ever notice how some of the best interfaces have these neat little panels that pop up right where you need them? Click a settings button and boom - there's your form right there. That's what popovers do best.

Settings panel in a popover

Clean way to show forms and controls without taking over the screen:

Loading component...

Built on Radix UI with all the smart positioning and keyboard stuff handled for you. It's one of those components that just works - figures out where to place itself, handles focus, plays nice with screen readers.

npx shadcn@latest add popover

When popovers make sense

You know that awkward spot between "this needs more than a tooltip" and "this doesn't need a whole dialog"? That's popover territory.

  • Keep things contextual - Info shows up right where it belongs
  • Save screen space - Hide secondary stuff until it's needed
  • Smart about placement - Won't get cut off by viewport edges
  • Handles focus properly - Keyboard navigation that actually works
  • Renders in portals - No more z-index headaches
  • Works with everything - Click, hover, focus, whatever you need

Useful popover patterns

Date picker

Because nobody wants to type dates manually:

Loading component...

Profile menu

Quick access to user stuff without a full dropdown:

Loading component...

These are the patterns you see everywhere because they work. Date pickers that don't suck, profile menus that feel snappy, settings panels that don't interrupt your flow.

Great for React apps

Works especially well in dashboards, admin panels, and anywhere you've got forms or controls that users need occasionally. The kind of stuff where a full page or modal would be overkill.

Drops right into Next.js projects. TypeScript definitions included. Plays nice with the shadcn ecosystem.

Built on solid foundations

Uses Radix UI under the hood, so you get all the good stuff without having to think about it:

  • Collision detection - Bumps away from screen edges automatically
  • Focus management - Tab navigation just works
  • Portal rendering - No weird clipping issues
  • Smooth animations - CSS variables for transitions that feel right
  • Flexible anchoring - Stick it to whatever element makes sense
  • Modal or not - Your choice on how it behaves
  • Smart dismissal - Click outside, press escape, whatever feels natural

API Reference

Popover

The root container that manages popover state and provides context.

PropTypeDefaultDescription
defaultOpenbooleanfalseDefault open state for uncontrolled usage
openboolean-Controlled open state
onOpenChange(open: boolean) => void-Callback when open state changes
modalbooleanfalseWhether popover should be modal

PopoverTrigger

The button that toggles the popover. By default, content positions against this element.

PropTypeDefaultDescription
classNamestring-Additional CSS classes
asChildbooleanfalsePass functionality to child element
childrenReact.ReactNode-Trigger content

Data attributes:

  • [data-state]: "open" | "closed"

PopoverContent

The panel that appears when the popover is open. Renders in a portal by default.

PropTypeDefaultDescription
classNamestring-Additional CSS classes
align"start" | "center" | "end""center"Alignment relative to trigger
side"top" | "right" | "bottom" | "left""bottom"Preferred side of trigger
sideOffsetnumber4Distance from trigger
alignOffsetnumber0Offset from aligned position
avoidCollisionsbooleantrueWhether to avoid viewport collisions
collisionPaddingnumber10Padding from viewport edges
arrowPaddingnumber0Padding between arrow and content edges
sticky"partial" | "always""partial"Sticky behavior when scrolling
hideWhenDetachedbooleanfalseHide when trigger becomes fully occluded

Data attributes:

  • [data-state]: "open" | "closed"
  • [data-side]: "left" | "right" | "bottom" | "top"
  • [data-align]: "start" | "end" | "center"

CSS variables:

  • --radix-popover-content-transform-origin: Transform origin for animations
  • --radix-popover-content-available-width: Available width in viewport
  • --radix-popover-content-available-height: Available height in viewport
  • --radix-popover-trigger-width: Width of the trigger element
  • --radix-popover-trigger-height: Height of the trigger element

PopoverAnchor

Optional element to position content against instead of the trigger.

PropTypeDefaultDescription
classNamestring-Additional CSS classes
asChildbooleanfalsePass functionality to child element

Event Handlers

The PopoverContent component supports several event handlers for fine-grained control:

HandlerTypeDescription
onOpenAutoFocus(event: Event) => voidCalled when focus moves to content on open
onCloseAutoFocus(event: Event) => voidCalled when focus returns to trigger on close
onEscapeKeyDown(event: KeyboardEvent) => voidCalled when Escape key is pressed
onPointerDownOutside(event: PointerEvent) => voidCalled when pointer is pressed outside
onFocusOutside(event: FocusEvent) => voidCalled when focus moves outside
onInteractOutside(event: Event) => voidCalled when interaction happens outside

Keyboard Navigation

KeyAction
SpaceOpens/closes the popover
EnterOpens/closes the popover
TabMoves focus to next focusable element
Shift + TabMoves focus to previous focusable element
EscapeCloses popover and returns focus to trigger

Positioning Patterns

PatternUse CaseConfiguration
Bottom alignedDropdown menusside="bottom" align="start"
Top tooltip styleHelp textside="top" align="center"
Side panelsContext menusside="right" align="start"
Corner dialogsUser profilesside="bottom" align="end"

Make them feel right

Few things to keep in mind so your popovers don't annoy people:

  • Don't cram everything in - Just the stuff that matters for what they're doing
  • Pick good spots - Usually bottom or right, but let collision detection do its thing
  • Test with real content - Make sure long text doesn't break your layout
  • Mobile matters - Fat fingers need bigger targets
  • Keyboard users exist - Tab through it, make sure it makes sense
  • Match the trigger - Click for settings, hover for previews, whatever feels obvious
  • Close when done - Don't make people hunt for the X button
  • Make it obvious - People should know what's clickable