Components
Popover
Contextual dialogs anchored to an interactive element
Default
Pass the trigger as an element and the dialog contents as children. The trigger opens the popover without a separate click handler.
<PopoverV2 accessibilityLabel="New feature" trigger={<ButtonV2>Open popover</ButtonV2>} > <div> <div className="mb2"> <Title headingLevel={2} size={5} > New feature </Title> </div> <Text size={2}> You can now estimate jobs from your settings. </Text> <div className="flex items-center justify-end gap1 mt3"> <ButtonV2 size="small" theme="tertiary" > Previous </ButtonV2> <ButtonV2 size="small"> Next </ButtonV2> </div> </div> </PopoverV2>
Controlled state
Control the popover when another part of the interface also needs to open or close it. Update state from onOpenChange so open and close requests stay synchronized.
function ControlledPopover() { const [isOpen, setIsOpen] = React.useState(false); return ( <PopoverV2 trigger={<ButtonV2>Open popover</ButtonV2>} isOpen={isOpen} onOpenChange={setIsOpen} accessibilityLabel="Estimate jobs" > <Title headingLevel={2} size={5}>Estimate jobs</Title> <Text size={2}>Create an estimate from your job settings.</Text> </PopoverV2> ); }
Positioning
Use position to choose the preferred side and alignment. React Aria automatically flips the popover when the preferred position would overflow the viewport.
The arrow tip sits 8px from the trigger by default. Use offset to override that gap in pixels when the context requires different spacing. The component accounts for the arrow size in every position, including when it flips.
<PopoverV2 accessibilityLabel="Popover positioned below" position="bottom-start" trigger={<ButtonV2>Open popover</ButtonV2>} > <Text size={2}> Popover content </Text> </PopoverV2>
Supported values are top-start, top, top-end, bottom-start, bottom, bottom-end, left-start, left, left-end, right-start, right, and right-end.
Accessibility
Give the dialog a concise accessibilityLabel that identifies its purpose. Use a visible heading in the content, and keep the trigger label specific to the action it performs. The popover does not lock page scrolling or add a blocking underlay. The dialog retains keyboard focus containment. Closing with the close button or Escape returns focus to the trigger. Clicking non-focusable background content does not dismiss the popover; interacting with a focusable control outside can close it.
Trigger requirements
Use a React Aria-compatible interactive element as the trigger. Do not wrap a non-interactive element or recreate the v1 ref callback, because that bypasses the keyboard and accessibility behavior supplied by DialogTrigger.
Props
PopoverV2
childrenrequiredContents displayed inside the popover.
TypeReact.ReactNodetriggerrequiredInteractive element that opens the popover. Use a React Aria-compatible component such as
ButtonV2orLinkV2so trigger semantics, focus, and keyboard behavior are preserved.TypeReact.ReactElementpositionPreferred position of the popover relative to its trigger. The popover automatically flips when there is not enough room in the preferred direction.
Type| 'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end' | 'left-start' | 'left' | 'left-end' | 'right-start' | 'right' | 'right-end'Default'top'offsetGap in pixels between the arrow tip and the trigger. Defaults to the 8px spacing token.
TypenumberDefaulttpV2SpaceXsmallisOpenControls whether the popover is open. Pair with
onOpenChangefor controlled usage.TypebooleandefaultOpenSets the initial open state for uncontrolled usage.
TypebooleanonOpenChangeCalled whenever the popover opens or closes.
Type(isOpen: boolean) => voidonCloseClickCalled when React Aria requests that the popover close, including the close button and Escape. Kept as a migration path from the V1
PopoverAPI.Type() => voidaccessibilityLabelAccessible name for the popover dialog.
TypestringDefault'Popover'dataTestIdSelector hook for automated tests.
Typestring