Popover

Atom
Floating panel with a title, supporting text, rich content such as form fields, and a single follow-up action, anchored to its trigger. Pass children to host custom content in the panel body, between the description and the action.

Playground

Every control sets a real prop of PopoverProps. The JSX below updates as you go.
Glass intensity
Frost and tint for every pane.
Project name
Props
title
string
description
string
Side
pick one
compact
boolean
actionLabel
string
JSX · PopoverProps
<Popover
title="Glass intensity"
description="Frost and tint for every pane."
bottom
actionLabel="Apply"
/>

Variants

5 examples from src/atoms/popover/popover.md, each rendered live from its own JSX.
Compact panel
<Popover compact comfortable anchored panelWidth={320} trigger="Filters" accessibilityLabel="Filters">
<Typography small muted>Choose the roles and pods to include.</Typography>
</Popover>
Draft saved
Your changes are kept as a draft until you publish them.
Inline
<Popover inline title="Draft saved" description="Your changes are kept as a draft until you publish them." actionLabel="Publish" />
Above
<Popover top trigger="Filter" title="Filter results" description="Show only the projects you own." actionLabel="Apply" />
Description only
<Popover trigger="What is a workspace?" description="A workspace groups your projects, members, and billing under one plan." />
The share popover is closed.
Controlled
<Stateful initial={false}>
{(open, setOpen) => (
<Column snug>
<Typography small muted>{open ? "The share popover is open." : "The share popover is closed."}</Typography>
<Popover
trigger="Share"
open={open}
onOpenChange={setOpen}
title="Share this project"
description="Anyone with the link can view it."
actionLabel="Copy link"
/>
</Column>
)}
</Stateful>

Anatomy

Glass intensity
Frost and tint for every pane.
Project name
1
Trigger
2
Panel
3
Arrow
4
Title
5
Description
6
Action
Dimmed parts appear only in some states or variants.

Props

20 props on PopoverProps, grouped as they are declared in source. Required props are marked *.
Prop
Type
Default
Description
Props
20 props
anchorRef
RefObject<View | null>
–
An existing trigger to anchor against; omits the built-in trigger and wrapper.
accessibilityLabel
string
–
Explicit name for a panel with custom content.
compact
boolean
false
Compact web application panel with an outside hairline and scrolling content.
comfortable
boolean
false
Roomier compact-panel content inset.
anchored
boolean
false
Keep the card anchored on narrow windows instead of adapting to a sheet.
alignEnd
boolean
false
Align the trailing edge of the card to its trigger.
panelWidth
number
–
Floating card width, clamped inside the overlay outlet.
maxHeight
number
–
Maximum height of the floating card; its compact contents scroll within it.
trigger
string
–
Label for the trigger button.
title
string
–
Heading shown at the top of the floating card.
description
string
–
Supporting line beneath the title.
children
ReactNode
–
Custom panel content (an input, a form row, any node), rendered in the card body between the description and the action row. Composes with the data-driven props.
actionLabel
string
–
When set, renders a primary action button at the bottom of the card.
top
boolean
false
Anchor the card ABOVE the trigger (it flips below when the room above is short). Placement axis: top > bottom.
bottom
boolean
false
Anchor the card BELOW the trigger, the default (it flips above when the room below is short).
inline
boolean
false
Static mode: render the card on its own with no trigger button (an always-visible inline panel). When set, the card is always shown and open is ignored. With top or bottom it points its beak at what it belongs to (below it with top, above it with bottom), from the end edge with alignEnd.
open
boolean
false
Controlled open state. Omit for uncontrolled (the trigger toggles it).
onOpenChange
(open: boolean) => void
–
Fired when the open state changes.
testID
string
–
E2E hook forwarded to the root element.
style
StyleProp<ViewStyle>
–
Outer layout composition only (width/flex within a parent), never a restyle hook.

Accessibility and keyboard

Keyboard
Tab
Shift+Tab
Cycles focus inside the panel
Escape
Closes when dismissible
Enter
Confirms in forms
Semantics
Roles
dialog
ARIA on web
aria-describedby
aria-label
aria-labelledby
aria-modal
From the docs
The trigger is a button that announces its popup as a dialog and whether it is expanded. Opening the card moves keyboard focus into the panel, once its placement has settled: a dialog named by its title (by the trigger's label when it has none) and described by its supporting line. A card pinned open (a controlled open with no change handler) is part of the page and takes no focus as it appears.
With a keyboard, Tab moves through the panel's controls as if the card sat right after its trigger, then on to the control after the trigger, and the card stays open: the anchored popover is non-modal on the web. Shift+Tab from the panel returns to the trigger, and Tab from the trigger re-enters the card. Escape closes it, and focus goes back to whatever opened it.
The sheet on phones is modal, as it covers and dims the page: its dialog is announced as modal, Tab and Shift+Tab keep to its controls and wrap at their ends, and a Tab from anywhere on the page behind it goes into it. Escape, the action or a tap on the scrim closes it, and focus goes back to whatever opened it.
On iOS and Android the open card is modal to VoiceOver and TalkBack: the page behind it is hidden from them, their focus moves to the card's first line, and when the card closes it returns to the trigger. The escape gesture and the Android back button close the card. Touch closes it with a tap anywhere outside it, and on phones a tap on the scrim above the sheet.

Platform skins

The playground's props on each platform: same tree, native shapes, type and touch sizes.
Share link
Anyone with the link can view.
Web
control 10 · field 10 · card 16 · Instrument Sans
Share link
Anyone with the link can view.
iOS
capsule controls · field 8 · card 12 · SF Pro · 44 pt
Share link
Anyone with the link can view.
Android
Material 3 stadium · field 4 · card 12 · Roboto · 48 dp

Usage

<Popover
trigger="Open popover"
title="Rename project"
description="Choose a name your team will recognize."
actionLabel="Rename"
>
<Input label="Project name" defaultValue="Identity Platform" />
</Popover>
On the web and Android the panel is the v4 card: 280 wide at the menu corner, the field hairline and the large shadow, a 15px display heading over its 14px description in the muted ink, and in solid mode a small diamond beak on the edge facing its trigger. iOS keeps the iPad popover, a rounder borderless card with a tapered beak toward its trigger.
The triggered card opens below its button by default and above it with top; either way it flips to the other side when its own lacks room, and the beak follows the side it took. At phone width a triggered card that can close is presented as a sheet on the bottom edge of the window, over the tab bar and a dimming scrim that glass on the web also blurs, its content kept clear of the home indicator: Dark Factory's sheet on the web, the iOS sheet on iPhone and the Material 3 bottom sheet on Android.
In glass mode the triggered card is a functional-layer glass panel beside its button, and the sheet a dense-layer one, legible over its scrim; focus enters once the card's placement has committed, and the inline card is a static in-flow panel. Solid mode paints the skin's own panel.

Tokens

Read from the playground render. Values follow the scheme and the ion hue.
--bf
--bls
--bw
--f-dp
--fd
--ft
--gl
--hl
--ion
--ion-fg
--ln2
--sf2
--sf3
--sf4
--sh-lg
--tx
--tx2

Related components