VayuUI

Popover

Displays rich content in a floating panel, triggered by a button.

Installation

npx vayu-ui init #one time only
npx vayu-ui add popover
npx vayu-ui add -t popover #with test case needs

Usage

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 asChild to 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-expanded on Popover.Trigger reflects the open/closed state.
    • aria-haspopup="dialog" on Popover.Trigger indicates a popup dialog.
    • role="dialog" on Popover.Content identifies it as a dialog.
    • aria-modal on Popover.Content is set to "true" when modal mode 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.

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 reference

Props

Popover (Root)

PropTypeDefaultDescription
openbooleanControlled open state.
onOpenChange(open: boolean) => voidCallback when open state changes.
defaultOpenbooleanfalseDefault open state for uncontrolled usage.
modalbooleanfalseShows a backdrop overlay when enabled.
childrenReactNodePopover subcomponents.
classNamestringAdditional CSS classes.

Popover.Trigger

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto child element instead of rendering a button.
disabledbooleanfalseDisables the trigger.
classNamestringAdditional CSS classes.

Popover.Content

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left""bottom"Placement side of the popover.
align"start" | "center" | "end""center"Alignment along the trigger axis.
sideOffsetnumber8Distance from trigger in pixels.
alignOffsetnumber0Alignment offset in pixels.
showArrowbooleanfalseShow a directional arrow pointing to the trigger.
avoidCollisionsbooleantrueFlip side if there is not enough viewport space.
childrenReactNodeContent to display inside the popover.
classNamestringAdditional CSS classes.

On this page