Skip to Content
Menu and Popover

Menu and Popover

Position temporary commands or ordinary form controls in the browser top layer.

Interactive example React 19 · local alpha

Ready

Usage

The example assumes the stylesheet and a Theme are already present.

import { Menu, Popover, Checkbox, Button } from "@pane-ui/react"; <> <Menu label="Collection actions" items={[ { id: "save", label: "Save for later", onSelect: () => console.log("Save"), }, { id: "share", label: "Share", disabled: true, onSelect: () => {} }, ]} /> <Popover label="Filter collection" title="Your view"> {({ close }) => ( <> <Checkbox label="Only favorites" /> <Button onClick={close}>Done</Button> </> )} </Popover> </>;

API

Prop / exportType / defaultPurpose
labelstring; required on bothText of the native Button trigger.
open, onOpenChangeControlled boolean with required callbackAlternatively omit open and use defaultOpen (false by default).
placementFloating UI placement; default "bottom-start"Position with viewport flip/shift/size correction.
triggerPropsButton props excluding children and managed popup ARIADisabled/loading, native events, styling and attributes.
Menu itemsMenuItem[]; requiredUnique id, plain string label, onSelect(event); optional disabled/destructive.
Popover titlestring; requiredNames the non-modal dialog surface.
Popover childrenReactNode or ({ close }) => ReactNodeOrdinary controls; render function can close after Apply/Cancel.
RefsHTMLButtonElement on bothRef targets the trigger, not the floating surface.

Behavior and composition

Menu uses arrow navigation, Home/End, typeahead and roving focus. Native button activation calls onSelect, then closes unless that event was prevented. Disabled items are skipped. It is a command menu: selectable items, custom renderers and nested submenus are not promised.

Popover is a non-modal dialog with ordinary Tab order. It focuses its first control and closes as focus leaves. Escape returns focus to the trigger; an outside click preserves focus on the outside control. Draft/apply state belongs to your application. Consumer trigger handlers run first and can prevent internal interaction. Disabled/loading triggers cannot open the popup through normal interactions.

The implementation uses Floating UI for positioning, dismissal and focus. It requires the native Popover API; panels occupy the top layer while remaining in their Theme subtree. Scroll/resize/layout changes update positioning and long panels can scroll. Default-open server markup is promoted to the top layer only after hydration.

A menu command may open a Dialog; pass the menu trigger ref as the dialog’s finalFocusRef when that is the appropriate return destination. Nested floating surfaces remain outside the alpha support contract.

Last updated on