Popover
Displays rich content in a floating panel, triggered by a button.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add popovernpx vayu-ui add -t popover #with test case needsUsage
Popover Example
Features
Alignment
Positions
Custom Trigger
<Popover>
<Popover.Trigger>Open Popover</Popover.Trigger>
<Popover.Content>
<div className="p-2">
<p>Set the dimensions for the layer.</p>
</div>
</Popover.Content>
</Popover>
<Popover>
<Popover.Trigger>With Arrow</Popover.Trigger>
<Popover.Content side="top" showArrow>
<div className="p-2">
<p>This popover appears above with an arrow.</p>
</div>
</Popover.Content>
</Popover>
<Popover>
<Popover.Trigger asChild>
<Button variant="primary">Custom Trigger</Button>
</Popover.Trigger>
<Popover.Content side="bottom" align="start" showArrow>
<div className="p-2">
<p>Using asChild with a custom trigger element.</p>
</div>
</Popover.Content>
</Popover>Anatomy
import { Popover } from 'vayu-ui';
<Popover>
<Popover.Trigger>Open</Popover.Trigger>
<Popover.Content side="bottom" align="center" sideOffset={8} showArrow>
{/* Content goes here */}
</Popover.Content>
</Popover>;- Popover — Root container. Manages open/close state and provides context to all subcomponents. Supports controlled and uncontrolled usage.
- Popover.Trigger — Button that toggles the popover. Supports
asChildto merge props onto a custom element. - Popover.Content — Floating panel with automatic positioning and collision detection. Renders conditionally when open.
Accessibility
- Keyboard Support:
Escape— Closes the popover and returns focus to the trigger.Enter/Space— Toggles the popover open/closed when focus is on the trigger.
- ARIA Attributes:
aria-expandedonPopover.Triggerreflects the open/closed state.aria-haspopup="dialog"onPopover.Triggerindicates a popup dialog.role="dialog"onPopover.Contentidentifies it as a dialog.aria-modalonPopover.Contentis set to"true"whenmodalmode is enabled.
- Focus Behavior:
- When the popover opens, focus moves to
Popover.Content. - When the popover closes (via Escape), focus returns to the trigger element.
- Clicking outside the trigger or content closes the popover.
- When the popover opens, focus moves to
Screen reader behavior
When the popover opens, the screen reader announces the dialog (via role="dialog") and the trigger's aria-expanded state updates to true. The content becomes focusable (tabIndex={-1}) so screen readers can navigate into it. In modal mode, aria-modal="true" restricts the assistive technology to only announce content within the popover. When the popover closes, focus returns to the trigger button and aria-expanded updates to false.
Component Folder Structure
Popover/
├── Popover.tsx # Root component with context provider, state, and click-outside handling
├── PopoverTrigger.tsx # Trigger button with asChild and keyboard support
├── PopoverContent.tsx # Positioned floating panel with auto-focus and arrow rendering
├── hooks.ts # Context, usePopover, and usePopoverPosition hook
├── types.ts # TypeScript type definitions
├── index.ts # Re-exports all components and types
└── README.md # Component usage referenceProps
Popover (Root)
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
onOpenChange | (open: boolean) => void | — | Callback when open state changes. |
defaultOpen | boolean | false | Default open state for uncontrolled usage. |
modal | boolean | false | Shows a backdrop overlay when enabled. |
children | ReactNode | — | Popover subcomponents. |
className | string | — | Additional CSS classes. |
Popover.Trigger
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge props onto child element instead of rendering a button. |
disabled | boolean | false | Disables the trigger. |
className | string | — | Additional CSS classes. |
Popover.Content
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" | Placement side of the popover. |
align | "start" | "center" | "end" | "center" | Alignment along the trigger axis. |
sideOffset | number | 8 | Distance from trigger in pixels. |
alignOffset | number | 0 | Alignment offset in pixels. |
showArrow | boolean | false | Show a directional arrow pointing to the trigger. |
avoidCollisions | boolean | true | Flip side if there is not enough viewport space. |
children | ReactNode | — | Content to display inside the popover. |
className | string | — | Additional CSS classes. |