Popover
Shows a few lines next to a control.
Opening
pressdefault
Token budgetThe most tokens one run may use before the agent stops and asks. Set per agent.
PopoverInfo
openOnHover
Usage
When to use it
- Use
- A small task beside its control: share a link, set one value, pick a filter.
- Use
- The explanation of a term beside it (PopoverInfo).
- Use
- A preview of a linked thing on hover, for a pointer (openOnHover).
- Not for
- A list of actions. Use Dropdown menu.
- Not for
- A one-line name for an icon button. Use Tooltip.
- Not for
- A decision the page must wait for. Use Dialog.
- Not for
- More than 320px of content. Use Sheet.
Rules
8 rules
- Must
- Use PopoverInfo for an info icon that explains a term, never a Tooltip. Because a tooltip never opens on touch and closes when the pointer leaves, so the definition is unreadable on a phone.
- Must
- Pass title (it names the button "About <title>") or label to PopoverInfo. Because without either every info button is named "More information" and a screen reader cannot tell them apart.
- Must
- Write plain text only in a PopoverInfo; put a link beside the term, or use a Popover. Because focus never enters a PopoverInfo, so a link inside it cannot be reached by keyboard.
- Must
- Make an openOnHover trigger a link that works on its own, and show nothing the linked page does not. Because touch and keyboard never see a hover preview, so the link has to reach the same facts alone.
- Never
- Put actions in a hover preview; move them to a DropdownMenu or the linked page. Because a peek closes when the pointer leaves and never opens on touch, so the actions slip away or never appear.
- Must
- Give a popover at most one ink Button; Done or Cancel beside it is variant="secondary" (paper). Because the popover's actions are one group, and two ink pills split the eye.
- Never
- Add a shadow or an arrow; the ring and the 6px offset tie the panel to its trigger. Because Glaze has no shadows, every shadow class draws nothing, and an arrow breaks the ring's one edge.
- Should
- Lead a hover preview with the name and one line of what it is, then two to four facts with numbers.
State order
4 states, highest first
- 1
- pinned
- 2
- open
- 3
- peeking
- 4
- closed
Accessibility
4 checks
- The panel is a dialog named by PopoverTitle; Tab moves through its content and leaving it closes it.
- A peek never takes focus; a pinned preview shows a Close preview button.
- PopoverInfo's text is also its button's description, so focus alone reads it.
- Hover previews never open on touch; PopoverInfo opens by tap.
Keyboard
3 keys
- Enter, Space
- Opens or closes it from the trigger; pins a peeking preview.
- Escape
- Closes this popover only and returns focus to the trigger.
- Tab
- Moves through the content; past the last control it closes and moves on.
Edge cases
6 edge cases
- Long content
- The title wraps and the panel scrolls inside the available height.
- Opened at a screen edge
- The panel flips and shifts to stay 8px inside.
- Phone, 390 wide
- The panel keeps 288px, or the available width when that is less.
- Inside a Dialog
- Escape closes the popover first; focus returns to its trigger.
- Right to left
- The panel lays out right to left inside an RTL portal scope.
- Reduced motion
- It cuts in and out instead of fading.
API
7 props
Popover open, defaultOpen, onOpenChangeBase UIdefaultfalsePopover defaultPreview'peeking' | 'pinned'PopoverTrigger openOnHover, delay, closeDelayboolean, numberdefaultfalse, 600, 300PopoverContent side, align, sideOffsetBase UIdefault'bottom', 'center', 6PopoverContent collisionPaddingnumberdefault8PopoverInfo title, labelReactNode, stringdefault'About ' + titlePopoverInfo side, alignBase UIdefault'top', 'center'
Tokens
15 tokens
--paper- #ffffff
--line- rgb(5 5 5 / 0.10)
--radius-overlay- 10px
--popover- 288px
--space-3- 12px
--type-label- 500 13px/1.35 var(--font-sans)
--type-body-sm- 400 13px/1.5 var(--font-sans)
--text-1- rgb(5 5 5 / 0.80)
--text-2- rgb(5 5 5 / 0.60)
--hover- rgb(5 5 5 / 0.06)
--pressed- rgb(5 5 5 / 0.10)
--z-overlay- 50
--dur-overlay- 200ms
--dur-state- 160ms
--ease-out- cubic-bezier(0.2, 0.8, 0.2, 1)