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>
<p>Popover content goes here.</p>
</Popover.Content>
</Popover>
<Popover>
<Popover.Trigger>With Arrow</Popover.Trigger>
<Popover.Content showArrow side="top">
<p>This popover has an arrow pointing to the trigger.</p>
</Popover.Content>
</Popover>
<Popover>
<Popover.Trigger>Aligned Start</Popover.Trigger>
<Popover.Content side="bottom" align="start">
<p>align="start"</p>
</Popover.Content>
</Popover>
<Popover>
<Popover.Trigger asChild>
<button className="...">Custom Trigger</button>
</Popover.Trigger>
<Popover.Content showArrow>
<p>Using asChild with a custom trigger element.</p>
</Popover.Content>
</Popover>Anatomy
import { Popover } from 'vayu-ui';
<Popover>
<Popover.Trigger>Trigger</Popover.Trigger>
<Popover.Content>Content goes here.</Popover.Content>
</Popover>;- Popover — Root container. Manages open/close state and provides context to children.
- Popover.Trigger — Button element that toggles the popover open or closed. Supports
asChildto merge props onto a custom element. - Popover.Content — Floating panel positioned relative to the trigger. Supports directional placement, arrow indicator, and collision avoidance.
Accessibility
- Keyboard Support:
Enter/Space— Toggle the popover open or closed.Escape— Close the popover and return focus to the trigger.
- ARIA Attributes:
aria-expandedonPopover.Triggerreflects the open/closed state.aria-haspopup="dialog"onPopover.Triggerindicates a dialog will open.role="dialog"onPopover.Contentidentifies it as a dialog.aria-modalonPopover.Contentreflects whether modal mode is enabled.
- Focus Behavior:
- Focus moves to
Popover.Contentwhen it opens. - Focus returns to the trigger when the popover closes.
- Clicking outside the popover closes it and returns focus to the trigger.
- Focus moves to
Screen reader behavior
When a user navigates to a popover trigger, the screen reader announces the button text and its expanded or collapsed state via aria-expanded. When the popover opens, focus moves to the content panel which has role="dialog". If the popover is in modal mode, aria-modal="true" is set and the underlying page content becomes inert. When the popover closes via Escape or an outside click, focus returns to the trigger button and the screen reader announces the trigger again.
Component Folder Structure
Popover/
├── Popover.tsx # Root component with context provider and open/close state
├── PopoverTrigger.tsx # Trigger button with asChild support
├── PopoverContent.tsx # Positioned floating content with arrow and collision avoidance
├── hooks.ts # Context, usePopover hook, and usePopoverPosition positioning logic
├── types.ts # TypeScript type definitions and arrow position classes
├── index.ts # Re-exports all components and types
└── README.md # Component usage referenceProps
Popover (Root)
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Open state when initially rendered. |
open | boolean | — | Controlled open state. |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
modal | boolean | false | Render with a backdrop overlay. |
children | ReactNode | — | Popover.Trigger and Popover.Content. |
className | string | — | Additional CSS classes. |
Popover.Trigger
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge props onto the child element instead of wrapping. |
disabled | boolean | false | Disable the trigger. |
children | ReactNode | — | Trigger label content. |
className | string | — | Additional CSS classes. |
Popover.Content
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side to render against the trigger. |
align | "start" | "center" | "end" | "center" | Preferred alignment against the trigger. |
sideOffset | number | 8 | Distance in pixels from the trigger. |
alignOffset | number | 0 | Offset in pixels from the start or end alignment. |
showArrow | boolean | false | Render an arrow pointing to the trigger. |
avoidCollisions | boolean | true | Automatically flip position to stay within the viewport. |
children | ReactNode | — | Popover content. |
className | string | — | Additional CSS classes. |