A small panel anchored to a button, wrapping the Base UI Popover. Non-modal by default, so the page behind stays interactive; for a plain text label, the lighter Tooltip is the better fit.

Playground

Every control maps to a prop. The Code tab always shows the markup for exactly what you've configured.

Variants

Four sides, and each flips to the opposite when there's no room; align (start, center, end) slides the panel along the chosen edge. Open each one: the panel scales in from the trigger's side.

States

Closed and open are the only two, and both are live: click a trigger. While open, the trigger carries data-popup-open and the panel data-open; a disabled trigger (disable the button you render) never opens.

Styling states

The trigger carries data-popup-open while open; the popup carries data-side and the data-starting-style/data-ending-style enter and exit hooks:

.ub-popover-trigger[data-popup-open] {
  background: var(--ub-bg-muted);
}

Props

Position lives on the content; the title and description wire the panel's accessible name and description automatically. The essentials, by part:

PropTypeDefaultDescription
PopoverRoot.openbooleanControlled state. Pair with onOpenChange; defaultOpen for uncontrolled.
PopoverRoot.onOpenChange(open: boolean) => voidCalled on every open and close, including Escape and outside clicks.
PopoverRoot.modalbooleanfalseTraps focus and blocks the page behind; prefer a dialog at that point.
PopoverTrigger.renderReactElementThe real control that opens the panel, usually a Bones Button.
PopoverContent.side"top" | "right" | "bottom" | "left""bottom"Preferred side; flips to the opposite when out of room.
PopoverContent.align"center" | "start" | "end""center"Alignment along the chosen side.
PopoverContent.sideOffsetnumber8Gap between the trigger and the panel, in pixels.
PopoverContent.initialFocusboolean | RefObject<HTMLElement | null> | (openType) => ...Where focus lands on open; defaults to the first focusable part.

Agent instructions

Working with a coding agent? Paste this into its context, or point it at llms.txt for the whole library.

PopoverRoot, PopoverTrigger, PopoverContent, PopoverTitle, PopoverDescription, PopoverClose, from @usebones/react.
- Structure: PopoverRoot wraps PopoverTrigger + PopoverContent; put PopoverTitle (names the panel), PopoverDescription, and any controls inside the content. PopoverClose closes it.
- Attach trigger and close to real controls via render={<Button ... />}; a disabled rendered button never opens.
- PopoverContent: side "bottom" (default) | "top" | "right" | "left", align "center" | "start" | "end", sideOffset (8). Escape and outside clicks dismiss; focus returns to the trigger.
- Non-modal by default; modal traps focus (prefer a dialog then). For a plain text label use Tooltip.
- Restyle in CSS via .ub-popover-popup, .ub-popover-title, .ub-popover-description, [data-popup-open] on the trigger, [data-open]/[data-side] on the popup, [data-starting-style]/[data-ending-style] for enter/exit. Tokens only.