Popover
Popover displays contextual information or actions in a floating container that appears relative to a trigger element. Unlike dialogs, popovers are non-modal and allow users to continue interacting with the background content.
import {Popover} from "@qualcomm-ui/react/popover"Examples
Simple
Basic popover using the simple API with a label and child content.
<Popover
label="Label"
trigger={<Button emphasis="primary">Show Popover</Button>}
>
Popover content
</Popover>
Composite
Build with the composite API for granular control. This API requires you to provide each subcomponent, but gives you full control over the structure and layout.
<Popover.Root>
<Popover.Anchor>
<Popover.Trigger>
<Button emphasis="primary">Show Popover</Button>
</Popover.Trigger>
</Popover.Anchor>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow />
<Popover.Label>Label</Popover.Label>
<Popover.Description>Description</Popover.Description>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
Emphasis
Use emphasis to control the visual style of the popover. Two emphasis options are available: neutral (default) and brand.
import type {ReactElement} from "react"
import type {QdsPopoverEmphasis} from "@qualcomm-ui/qds-core/popover"
import {Button} from "@qualcomm-ui/react/button"
import {Popover} from "@qualcomm-ui/react/popover"
import {Portal} from "@qualcomm-ui/react-core/portal"
const emphasisOptions: QdsPopoverEmphasis[] = ["neutral", "brand"]
export function PopoverEmphasisDemo(): ReactElement {
return (
<div className="flex gap-4">
{emphasisOptions.map((emphasis) => (
<Popover.Root key={emphasis} emphasis={emphasis}>
<Popover.Anchor>
<Popover.Trigger>
<Button emphasis="primary">{emphasis}</Button>
</Popover.Trigger>
</Popover.Anchor>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Arrow />
<Popover.Label>Label</Popover.Label>
<Popover.Description>
This is a {emphasis} popover.
</Popover.Description>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
))}
</div>
)
}Accessibility
- The anchor element is automatically associated with the popover:
- When the popover is visible, the anchor element receives the
aria-controlsandaria-expandedattributes. - The anchor element's
aria-haspopupis always set to'true'. - When the
Popover.Labelcomponent is supplied, the overlay panel'saria-labelledbyattribute is set to the id of the label. - When the
Popover.Descriptioncomponent is supplied, the overlay panel'saria-describedbyattribute is set to the id of the label.
NOTE
Don't worry about supplying id's to the label, description or popover. If these aren't provided, they'll be generated automatically.
API
<Popover>
The Popover extends the Popover.Root with the following props:
| Prop | Type | Default |
|---|---|---|
Props applied to the anchor component. | PopoverAnchorProps | |
Props applied to the arrow component. | PopoverArrowProps | |
Props applied to the content component. | PopoverContentProps | |
Optional description text for the popover. | ||
Props applied to the description component. | PopoverDescriptionProps | |
Whether to hide the arrow. | boolean | false |
Optional label text for the popover. | ||
Props applied to the label component. | ||
Props applied to the portal component. | { | |
Props applied to the positioner component. | PopoverPositionerProps |
PopoverAnchorPropsPopoverArrowPropsPopoverContentPropsPopoverDescriptionPropsboolean{
container?:
| HTMLElement
| RefObject<HTMLElement>
disabled?: boolean
}
PopoverPositionerPropsComposite API
<Popover.Root>
| Prop | Type | Default |
|---|---|---|
Whether to automatically set focus on the first focusable
content within the popover when opened. | boolean | true |
Whether to close the popover when the escape key is pressed. | boolean | true |
Whether to close the popover when the user clicks outside the popover. | boolean | true |
The initial open state of the popover when rendered.
Use when you don't need to control the open state of the popover. | boolean | |
The document's text/writing direction. | 'ltr' | 'rtl' | 'ltr' |
The style variant of the popover. | | 'neutral' | 'neutral' |
A root node to correctly resolve document in custom environments. i.e.,
Iframes, Electron. | () => | |
The ids of the popover elements. These will be automatically generated if
omitted. | Partial<{ | |
Whether to synchronize the present change immediately or defer it to the next
frame | boolean | |
The element to focus on when the popover is opened. | () => HTMLElement | |
When true, the component will not be rendered in the DOM until it becomes
visible or active. | boolean | false |
Whether the popover should be modal. When set to true:- interaction with outside elements will be disabled - only popover content will be visible to screen readers - scrolling is blocked - focus is trapped within the popover | boolean | false |
Function called when the escape key is pressed | ( | |
Function called when the animation ends in the closed state | VoidFunction | |
Function called when the focus is moved outside the component | ( | |
Function called when an interaction happens outside the component | ( | |
Function invoked when the popover opens or closes
| ( | |
Function called when the pointer is pressed down outside the component | ( | |
Function called when this layer is closed due to a parent layer being closed | ( | |
The controlled open state of the popover | boolean | |
Returns the persistent elements that: - should not have pointer-events disabled - should not trigger the dismiss event | Array< | |
Whether the popover is portalled. This will proxy the tabbing behavior
regardless of the DOM position of the popover content. | boolean | true |
The options used to position the popover content. | ||
Whether the node is present (controlled by the user) | boolean | |
On close, restore focus to the element that triggered the open event. | boolean | true |
Whether to allow the initial presence animation. | boolean | false |
When true, the component will be completely removed from the DOM when it
becomes inactive or hidden, rather than just being hidden with CSS. | boolean | false |
booleanbooleanbooleanboolean'ltr' | 'rtl'
| 'neutral'
| 'brand'
() =>
| Node
| ShadowRoot
| Document
Partial<{
anchor: string
arrow: string
closeTrigger: string
content: string
description: string
positioner: string
title: string
trigger: string
}>
boolean() => HTMLElement
booleanbooleantrue:- interaction with outside elements will be disabled
- only popover content will be visible to screen readers
- scrolling is blocked
- focus is trapped within the popover
(
event: KeyboardEvent,
) => void
VoidFunction(
event: FocusOutsideEvent,
) => void
(
event: InteractOutsideEvent,
) => void
(
open: boolean,
) => void
- open:The next value of the open state.
(
event: PointerDownOutsideEvent,
) => void
(
event: CustomEvent<{
originalIndex: number
originalLayer: HTMLElement
targetIndex: number
targetLayer: HTMLElement
}>,
) => void
booleanArray<
() => Element
>
- should not have pointer-events disabled
- should not trigger the dismiss event
booleanbooleanbooleanbooleanbooleanThis section describes the elements of the Popover's composite API.
<Popover.Label>
| Prop | Type |
|---|---|
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
string| ReactElement
| ((
props: object,
) => ReactElement)
Data Structures
PopoverPositioningOptions
| Prop | Type | Default |
|---|---|---|
The minimum padding between the arrow and the floating element's corner. | number | 4 |
The overflow boundary of the reference element | () => | |
Whether the popover should fit the viewport. | boolean | |
Whether to flip the placement when the floating element overflows the boundary. | | boolean | true |
Function that returns the anchor rect | ( | |
The main axis offset or gap between the reference and floating element | number | 8 |
Whether the popover should be hidden when the reference element is detached | boolean | |
Options to activate auto-update listeners | | boolean | true |
The offset of the floating element | { | |
Function called when the placement is computed | ( | |
Function called when the floating element is positioned or not | (data: { | |
The virtual padding around the viewport edges to check for overflow | number | |
Whether the floating element can overlap the reference element | boolean | false |
The initial placement of the floating element | | 'bottom' | 'top' |
Whether to make the floating element same width as the reference element | boolean | |
The secondary axis offset or gap between the reference and floating elements | number | |
Whether the popover should slide when it overflows. | boolean | |
The strategy to use for positioning | | 'absolute' | 'absolute' |
A callback that will be called when the popover needs to calculate its
position. | (data: { |
number() =>
| 'clippingAncestors'
| Element
| Array<Element>
| {
height: number
width: number
x: number
y: number
}
boolean| boolean
| Array<
| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
>
(
element:
| HTMLElement
| VirtualElement,
) => {
height?: number
width?: number
x?: number
y?: number
}
numberboolean| boolean
| {
ancestorResize?: boolean
ancestorScroll?: boolean
animationFrame?: boolean
elementResize?: boolean
layoutShift?: boolean
}
{
crossAxis?: number
mainAxis?: number
}
(
data: ComputePositionReturn,
) => void
(data: {
placed: boolean
}) => void
numberboolean| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
booleannumberboolean| 'absolute'
| 'fixed'
(data: {
updatePosition: () => Promise<void>
}) => void | Promise<void>