apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
Popover
Variant↳ other

Overlays

Popover

Interactive floating panel — Tooltip\

Overview

<Popover /> is the canonical interactive floating-panel primitive — Tooltip's focusable cousin. Where Tooltip is read-only and pointer-events: none, Popover does receive focus, can host arbitrary interactive content (forms, lists, buttons), and participates in the engine's full overlay lifecycle: positioning, portaling, focus trapping, escape stack, outside-click.

It is the first compound overlay in the DS — Popover.Trigger + Popover.Content + Popover.Arrow + Popover.Close — and the canonical shape Menu, Select, Combobox will copy.

Overview — account menu trigger + open panel

Loading preview…
Overview.tsx

When to use

  • A small floating panel of related actions: "More options" → 3-button menu.
  • An inline form fragment (subscribe, share, set status).
  • A "click to expand" detail card — link previews, hover-cards (with openOnHover later).
  • "Are you sure?" confirmation patterns near the destructive trigger.
  • Notification trays, account menus.

When NOT to use

  • The content is purely a hint with no interactivity → use <Tooltip />.
  • The content is critical and blocks the page → use <Modal />.
  • The content is a list of actions → use <Menu />.
  • The content is a <select>-style chooser → use <Select /> or <Combobox />.

Anatomy

text
<Popover>
  <Popover.Trigger> button </Popover.Trigger>
  <Popover.Content>
    arbitrary content
    <Popover.Arrow /> (optional)
    <Popover.Close /> (optional)
  </Popover.Content>
</Popover>
<Popover>
  <Popover.Trigger> button </Popover.Trigger>
  <Popover.Content>
    arbitrary content
    <Popover.Arrow /> (optional)
    <Popover.Close /> (optional)
  </Popover.Content>
</Popover>
  • Popover — context provider. Owns open, setOpen, the trigger and floating refs, and the lifecycle hooks (useEscapeStack, useOutsideClick).
  • Popover.Trigger — clones a single child (asChild, default), attaching ARIA + click handlers. Or render an inline <button> when asChild={false}.
  • Popover.Content — the portal-rendered, positioned, focus-trapped, animated surface. Carries the visual axes (variant / size / color / placement / offset / showArrow).
  • Popover.Arrow — optional SVG arrow positioned by Floating UI's middleware.
  • Popover.Close — built-in × button in the corner; calls setOpen(false).

Variants

Three variants of the Content surface — all elevated (shadow-lg), all rounded:

  • solid — paper background + neutral border. Default. Color-neutral; color is ignored.
  • outline — paper background + 1px colored border. Brand-aligned popovers.
  • soft — subtle tinted background + low-opacity colored border. Editorial popovers.

The 3 variants × 7 colors compound matrix has 14 active cells (solid ignores color, outline and soft use one row each). Adding a new color = palette entry + 2 compound rows.

Sizes

SizePaddingMin-widthMax-widthArrow size
smp-3min-w-48max-w-xs12×6
mdp-4min-w-56max-w-sm16×8
lgp-6min-w-72max-w-md20×10

Placement

Same 12-placement vocabulary as Tooltip (top-start / top / top-end / right-start / …). Floating UI's flip middleware automatically swaps to the opposite side at viewport edges; the post-flip placement is reflected on the floating element via data-placement.

Behavior

PropDefaultEffect
modalfalseWhen true, adds a backdrop + aria-modal="true" + aria-haspopup="dialog". Use sparingly.
trapFocustrueFocus moves into Content on open; Tab cycles inside; focus returns to trigger on close.
closeOnEscapetrueEsc closes the topmost popover (escape-stack ordering).
closeOnOutsideClicktruePointer-down outside trigger + content closes the popover.
showArrow (on Content)falsePopovers feel like panels, not speech bubbles. Default off.
offset (on Content)8Px gap between trigger and content. Tooltip uses 6; Popover is slightly more spacious.

Accessibility

  • Trigger carries aria-haspopup ('true' for non-modal, 'dialog' for modal), aria-expanded, aria-controls={contentId} while open, and data-state="open"|"closed".
  • Content carries role="dialog", aria-labelledby={triggerId}, and (for modal) aria-modal="true".
  • Focus management (when trapFocus={true}):
    • On open: focus moves to initialFocus if provided, else first focusable child, else Content itself (which carries tabIndex={-1}).
    • Tab cycles inside Content via the engine's useFocusTrap.
    • On close: focus returns to the trigger.
  • Escape closes via the engine's useEscapeStack — only the topmost popover closes per press, so nested popovers unwind cleanly.
  • Outside click uses pointerdown (not click) for capture-phase responsiveness — same approach Radix uses.
  • Close button carries aria-label="Close" by default; override via aria-label prop.
  • axe-core: zero violations across the full variant × color × open-state matrix.

Examples

Basic

Loading preview…
Basic.tsx

Variants

Loading preview…
Variants.tsx

Sizes

Loading preview…
Sizes.tsx

Colors

Loading preview…
Colors.tsx

Placements

Loading preview…
Placements.tsx

WithArrow

Loading preview…
WithArrow.tsx

WithCloseButton

Loading preview…
WithCloseButton.tsx

ConfirmAction

Loading preview…
ConfirmAction.tsx

FormInside

Loading preview…
FormInside.tsx

NestedPopover

Loading preview…
NestedPopover.tsx

Controlled

Loading preview…
Controlled.tsx

ModalPopover

Loading preview…
ModalPopover.tsx

Theming

tsx
defineTheme({
  components: {
    Popover: {
      defaultProps: { /* root behavior props — modal/trapFocus/etc. */ },
      styleOverrides: {
        content: 'shadow-xl',
        arrow: '',
        close: 'text-fg-default',
        backdrop: 'bg-fg-default/40',
      },
    },
  },
});
defineTheme({
  components: {
    Popover: {
      defaultProps: { /* root behavior props — modal/trapFocus/etc. */ },
      styleOverrides: {
        content: 'shadow-xl',
        arrow: '',
        close: 'text-fg-default',
        backdrop: 'bg-fg-default/40',
      },
    },
  },
});

Per-instance overrides via <Popover.Content className sx style /> merge on top of the theme overrides, which merge on top of the recipe — same precedence as everywhere else in the DS.

Props

PropTypeDefaultDescription
closeOnEscapeboolean—Default: `true`. Esc closes the topmost Popover (escape-stack ordering).
closeOnOutsideClickboolean—Default: `true`. Pointerdown outside trigger + content closes the Popover.
defaultOpenboolean—Initial `open` for the uncontrolled case. Default: `false`.
modalboolean—When `true`, the Popover blocks pointer events on the rest of the page via a backdrop and sets `aria-modal="true"` on Content. Use sparingly — `<Modal>` is the right primitive for actual modals; `modal=true` on a Popover is for tactical exceptions (e.g. a complex date picker that needs to capture clicks but isn't full-screen). Default: `false`.
onOpenChange(open: boolean) => void—Notified whenever the `open` value changes (controlled or uncontrolled).
openboolean—Controlled `open`. When omitted, the popover manages its own state via `defaultOpen`.
trapFocusboolean—When `true`, focus is trapped inside `<Popover.Content>` while open and restored to the trigger on close. Default: `true`. Disable for split-panel patterns where Tab should leak back to the page.