Skip to content

Popover

A click-triggered floating dialog anchored to a trigger element.

<Popover {...args} content={popoverContent} padding={3}>
<Button label="Open popover" />
</Popover>
<div
style={{
display: 'grid',
gap: 24,
justifyItems: 'center',
padding: '80px',
}}>
<Popover
content={popoverContent}
label="Above"
padding={3}
placement="above">
<Button label="Above" />
</Popover>
<HStack gap={6}>
<Popover
content={popoverContent}
label="Start"
padding={3}
placement="start">
<Button label="Start" />
</Popover>
<Popover
content={popoverContent}
label="End"
padding={3}
placement="end">
<Button label="End" />
</Popover>
</HStack>
<Popover
content={popoverContent}
label="Below"
padding={3}
placement="below">
<Button label="Below" />
</Popover>
</div>
<HStack gap={4} style={{padding: '40px'}}>
<Popover
alignment="start"
content={popoverContent}
label="Start"
padding={3}
placement="below">
<Button label="Start" />
</Popover>
<Popover
alignment="center"
content={popoverContent}
label="Center"
padding={3}
placement="below">
<Button label="Center" />
</Popover>
<Popover
alignment="end"
content={popoverContent}
label="End"
padding={3}
placement="below">
<Button label="End" />
</Popover>
</HStack>
<HStack gap={2}>
<Button
label={isOpen ? 'Close externally' : 'Open externally'}
onClick={() => setIsOpen(v => !v)}
variant="secondary"
/>
<Popover
content={popoverContent}
isOpen={isOpen}
label="Controlled"
onOpenChange={setIsOpen}
padding={3}
placement="below">
<Button label="Trigger" />
</Popover>
</HStack>
<Popover {...args} content={popoverContent} isEnabled={false} padding={3}>
<Button label="Disabled popover" />
</Popover>
<Popover
{...args}
content={popoverContent}
hasCloseButton={false}
padding={3}>
<Button label="No close button" />
</Popover>
<Popover
{...args}
content={<Text as="p">This popover matches the trigger width.</Text>}
padding={3}>
<Button label="Wide trigger button" />
</Popover>
<Popover
{...args}
content={<Text as="p">A fixed-width popover for richer panels.</Text>}
padding={3}>
<Button label="Open fixed panel" />
</Popover>
<Popover
content={
<VStack gap={2}>
<Text as="p">Outer popover content</Text>
<Popover
content={
<VStack gap={2}>
<Text as="p">Inner popover content</Text>
<Button label="Apply" size="sm" variant="primary" />
</VStack>
}
label="Inner settings"
padding={3}>
<Button label="Open inner popover" size="sm" />
</Popover>
</VStack>
}
label="Outer settings"
padding={3}>
<Button label="Open outer popover" />
</Popover>

A click-triggered floating dialog anchored to a trigger element.

PropTypeDefaultDescription
alignment"center" | "end" | "start"'start'Alignment along the placement axis.
anchorRefRefObject<HTMLElement | null>External trigger element. When provided without children, Popover attaches click and ARIA behavior directly to this element.
childrenReactNodeTrigger content. Must contain a <button> or [role="button"].
classNamestringAdditional CSS class names applied to the popover content.
closeButtonLabelstring'Close popover'Label for the hidden close button.
content*ReactNodeContent displayed inside the popover dialog.
data-testidstringTest ID applied to the popover content.
hasAutoFocusbooleantrueWhether to focus the first focusable item after opening.
hasCloseButtonbooleantrueWhether to include a keyboard-accessible close button.
idstringId applied to the popover content element. Falls back to a generated id. Supply this when another element needs a stable aria-controls reference to the popover.
isDismissablebooleantrueWhether clicking outside or pressing Escape closes the popover.
isEnabledbooleantrueWhether trigger interactions open the popover.
isOpenbooleanControlled open state.
labelstringAccessible label for the popover dialog.
offsetXnumberGap in pixels between the popover and its trigger along the inline axis (for start/end placements). Applied as a logical margin so it stays on the trigger-facing side even when the popover flips.
offsetYnumberGap in pixels between the popover and its trigger along the block axis (for above/below placements). Applied as a logical margin so it stays on the trigger-facing side even when the popover flips.
onOpenChange(isOpen: boolean) => voidCallback fired when open state changes.
padding0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 100Inner padding of the popover content.
placement"end" | "start" | "above" | "below"'below'Position relative to the trigger.
refRef<HTMLDivElement>Ref forwarded to the popover content element.
role'dialog' | 'menu''dialog'ARIA role for the floating content.
styleCSSPropertiesInline styles applied to the popover content.
widthnumber | stringWidth of the popover content.