Popover
A headless, accessible popover with smart positioning, optional arrow, and optional modal focus trap.
Features
- Controlled or uncontrolled
- Modal or non-modal
- Flexible placement
- Optional arrow
- Automatic focus management
- Escape and outside-click dismissal
- Portal rendering
- Accessible labelling
Installation
npm install @ariaui/popover
Examples
Anchored floating surface with optional arrow and optional modal focus trap. Positioning stays in sync with the trigger.
Popover
A headless, accessible popover example.
No preview output yet.
Framer Motion
A popover content surface animated by Framer Motion through asChild composition.
No preview output yet.
Anatomy
import * as Popover from "@ariaui/popover";
export default function Example() {
return (
<Popover.Root>
<Popover.Trigger />
<Popover.Content>
<Popover.Heading />
<Popover.Description />
<Popover.Close />
</Popover.Content>
</Popover.Root>
);
}
API Reference
Root
Context provider and state container for the popover. Manages open state, positioning, and modal behavior.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
modal | boolean | false |
placement | 'top' | 'right' | 'bottom' | 'left' | '<side>-start' | '<side>-end' | 'bottom' |
offset | number | 0 |
Trigger
Button that toggles the popover open and closed.
| Attribute | Values |
|---|---|
| aria-haspopup | dialog |
| aria-expanded | true when open |
| aria-controls | ID of the Content element |
| [data-state] | open | closed |
Content
Floating panel containing the popover body. Portals to document.body, positions itself against Trigger, and unmounts when closed.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
arrow | boolean | false |
arrowClassName | string | — |
loop | boolean | true |
| Attribute | Values |
|---|---|
| role | dialog |
| aria-modal | true when modal |
| aria-labelledby | ID of the Heading |
| aria-describedby | ID of the Description |
| [data-side] | top | right | bottom | left |
Heading
Accessible title for Content. Registered as aria-labelledby on Content.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
Description
Accessible description for Content. Registered as aria-describedby on Content.
Close
Button that closes the popover when clicked.
Keyboard
| Shortcut | Action |
|---|---|
| Enter/Space | When focus is on Trigger, opens the popover and moves focus to the first focusable element in Content. |
| Tab | When the popover is open, moves focus to the next focusable element. In modal mode, focus cycles within Content. |
| Shift+Tab | Moves focus to the previous focusable element. In modal mode, focus cycles within Content. |
| Esc | Closes the popover and returns focus to the Trigger. |
Accessibility
Popover follows the WAI-ARIA Dialog (Modal) pattern with a non-modal mode for lightweight surfaces:
Triggerexposesaria-haspopup="dialog",aria-expanded, andaria-controlspointing at Content.Contentrenders withrole="dialog",aria-modalmatching themodalprop, anddata-sidefor styling.Headingregisters its id asaria-labelledbyon Content;Descriptionregisters asaria-describedby.- When
modalis true, focus is trapped in Content and interaction with the rest of the page is blocked. - When
modalis false, focus moves into Content on open but can leave naturally via Tab. - Escape closes the popover and returns focus to the Trigger.
- Content is portaled to
document.body, avoiding ancestor clipping and stacking issues.