Popover
A floating panel anchored to a trigger, on the floating surface in the dropdown layer.
import { Popover } from "@butteryui/core";Demo
When to use it
Use it for
- Small forms or option lists that belong to one control
- Anything that should close on Escape or an outside click
Not for
- Lists of actions: use Menu
- Picking one value from a list: use Select
- Hover hints: use Tooltip
- Blocking decisions: use Dialog
Examples
Card nickname
A popover whose open state lives in the example, so the form inside can close it once the saved card has a nickname.
Gift card size
A trigger that opens the gift card's printed sizes; picking one closes the popover and shows on the trigger.
Order filter
A list's filter in a popover beside its title: each roast it toggles filters the orders at once.
Orders
Showing 6 of 6 orders
Harbor blend
Medium
Kiambu washed
Light
Night shift
Dark
Guji natural
Light
Espresso no. 4
Dark
Huila honey
Medium
Variants and states
Sides
8px from the trigger; it flips when there isn't room.
Long content
Taller than the space available, so it scrolls inside.
Scrim
A blurred scrim under a menu that opens over content; clicking it closes the menu.
Props
Popover
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | Whether the popover is open. Pair with onOpenChange to control it. | |
defaultOpen | boolean | false | Whether it starts open when uncontrolled. Defaults to false. |
onOpenChange | ((open: boolean) => void) | Called when the popover opens or closes. | |
modal | boolean | false | Keep focus inside and make the page inert while open. Defaults to false. |
entrance | "grow" | "instant" | "grow" from the trigger with a fade, or "instant", complete in the next frame, as app chrome moves.
Defaults to what's set around it ("instant" inside AppShell layout="sidebar"), else "grow". | |
children | ReactNode | The trigger and content: Popover.Trigger, Popover.Content and, optionally, Popover.Anchor. |
Popover.Anchor
It also takes ComponentPropsWithRef<typeof RadixPopover.Anchor>.
Popover.Close
It also takes ComponentPropsWithRef<typeof RadixPopover.Close>.
Popover.Content
| Prop | Type | Default | Description |
|---|---|---|---|
scrim | "dim" | "blur" | Covers the page behind the open popover: "blur" for menus that open over content, "dim" to set
it apart further. It fades in and out with the panel, and clicking it closes the popover. Defaults to
no scrim. |
It also takes Omit<ComponentPropsWithRef<typeof RadixPopover.Content>, "sideOffset" | "collisionPadding" | "avoidCollisions" | "forceMount" | "asChild">.
Popover.Trigger
It also takes ComponentPropsWithRef<typeof RadixPopover.Trigger>.
Accessibility
The trigger gets aria-expanded and aria-controls; the content is a dialog that takes focus on open, closes on Escape and returns focus to the trigger. In a field holding an unsaved edit, the first Escape puts the field back.
| Keys | What they do |
|---|---|
| Enter or Space | Opens it from the trigger and moves focus to the first control inside, or to the panel when it has none |
| Tab or Shift+Tab | Moves through the controls inside it, wrapping from the last to the first |
| Escape | Closes it and puts focus back on the trigger; in a field holding an unsaved edit, the first Escape puts the field back |
Motion
It appears with a `Presence` preset and leaves faster than it came, in about 60% of the time.
With reduced motion: It fades in and out over 100ms without growing from the trigger, and so does its scrim; with entrance="instant", the panel and its scrim show and go at once either way.
Layout
It's as wide and tall as its content, up to the room beside its trigger, and scrolls inside past that. It opens 8px from its trigger, flips or shifts to stay 8px inside the window and never covers the trigger; what's inside it brings its own hit areas.