Headless hook for click-triggered popovers with focus trapping. Combines useLayer with useFocusTrap, auto-focus, light dismiss, Escape handling, and an optional hidden close button for accessible dialog-like popover behavior. Every painted surface emits the canonical popover target and deprecated popover-surface compatibility alias. A custom composition needing a distinct stable seam should pass and document its own surfaceTarget.
Callback fired when the popover is hidden. Use this to return focus to the trigger when needed.
xstyle
StyleXStyles
StyleX styles applied to the popover content wrapper, after the default surface styles.
hasLightDismiss
boolean · optional · default true
Whether clicking outside dismisses the popover.
hasEscapeDismiss
boolean · optional · default true
Whether pressing Escape dismisses the popover. Only takes full effect together with hasLightDismiss: false, since native light dismiss also closes on Escape.
hasAutoFocus
boolean · optional · default true
Whether to focus the first genuine content control when opened. Dialogs with none fall back to the labeled surface; the generated close control is excluded from initial focus.
hasCloseButton
boolean · optional · default true
Whether to include a hidden close button that appears for keyboard users.
closeButtonLabel
string · optional · default 'Close popover'
Accessible label for the hidden close button.
dialogLabel
string
Accessible label for the popover dialog (only applies when role is "dialog"). Provide one when there is no visible title.
role
'dialog' | 'none' · optional · default 'dialog'
ARIA role on the content wrapper. Use "dialog" for genuine dialog content; use "none" for listbox/menu popups whose own content role should be exposed and whose trigger keeps DOM focus.
isModal
boolean · optional · default true
Whether a dialog-role popover is modal (aria-modal). Only applies when role is "dialog".
hasSurface
boolean · optional · default true
Whether to apply the default popover surface background, radius, and shadow.
surfaceTarget
string
Optional component-owned refinement target on the painted surface, without the astryx- prefix. Use and document one when a direct hook composition needs distinct theme reachability. Do not use popover-surface; it is a deprecated compatibility alias of the canonical popover target.
Returns
Name
Type and behavior
triggerRef
(el: HTMLElement | null) => void
Ref callback to attach to the trigger element for CSS anchor positioning.
contentRef
RefObject<HTMLDivElement | null>
Ref for the popover content container used by focus trapping.
anchorId
string
CSS anchor name for advanced positioning cases.
show
(options?: {skipAutoFocus?: boolean}) => void
Imperatively show the popover. skipAutoFocus preserves current focus for input-triggered popovers.
Render function for anchor-positioned popover content. Pass placement and alignment here. Logical: start/end resolve against the popover's own inherited direction (RTL mirrors in pure CSS).
Preview loads on approachPreview loads on approach
Exact source · popover-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.
'use client';
import {useState} from 'react';
import {Popover} from '@astryxdesign/core/Popover';
import {Button} from '@astryxdesign/core/Button';
import {VStack} from '@astryxdesign/core/Layout';
import {Text, Heading} from '@astryxdesign/core/Text';
import {Divider} from '@astryxdesign/core/Divider';
export default function PopoverShowcase() {
const [isOpen, setIsOpen] = useState(false);
return (
<Popover
isOpen={isOpen}
onOpenChange={setIsOpen}
hasAutoFocus={false}
placement="below"
label="Settings"
width={280}
content={
<VStack gap={3}>
<Heading level={4} tabIndex={0}>
Settings
</Heading>
<Divider />
<Text type="body">
Notifications, dark mode, and sound preferences.
</Text>
</VStack>
}>
<Button label="Settings">Settings</Button>
</Popover>
);
}
Usage
Headless hook for click-triggered popovers with focus trapping. Combines useLayer with useFocusTrap, auto-focus, light dismiss, Escape handling, and an optional hidden close button for accessible dialog-like popover behavior. Every painted surface emits the canonical popover target and deprecated popover-surface compatibility alias. A custom composition needing a distinct stable seam should pass and document its own surfaceTarget.
Use for interactive content such as menus, pickers, forms, and command panels that need focus management.
Prefer the Popover component for standard trigger-content pairs; use the hook for custom trigger patterns.
Use popover as the broad surface target. Popover-surface remains supported compatibility output, but new theme source uses the canonical key.
When a custom composition needs its own theme refinement, pass and document an owned surfaceTarget such as selector-popup. It refines the Popover surface rather than creating another anatomy part.