Popover
Content anchored to the element that opened it, such as a small form or an explanation, without leaving the page.
A popover opens next to its trigger with content the reader can interact with: a short form that edits one value, a set of options, an explanation. The page behind stays usable, unlike behind a dialog. For a label that only names an icon button, use a tooltip; for a preview of a link, a hover card.
// apps/docs/examples/ui/popover.tsx'use client';
import {useState} from 'react';import {InfoIcon} from 'lucide-react';
import {Button} from '@workspace/active-ui/components/primitives/button';import { Field, FieldLabel,} from '@workspace/active-ui/components/primitives/field';import {Input} from '@workspace/active-ui/components/primitives/input';import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger,} from '@workspace/active-ui/components/primitives/popover';
/** * Content anchored to the element that opened it: a short form that edits * one value in place, and an explanation behind an icon button. The page * stays usable; a click outside or Escape closes the popover. */export default function PopoverExample() { const [open, setOpen] = useState(false); const [rate, setRate] = useState('7.5'); const [draft, setDraft] = useState(rate); return ( <div className="flex flex-wrap items-center justify-center gap-4"> <Popover open={open} onOpenChange={(next) => { setOpen(next); if (next) setDraft(rate); }} > <PopoverTrigger render={<Button variant="outline" />}> Contribution rate: {rate}% </PopoverTrigger> <PopoverContent className="w-72"> <PopoverHeader> <PopoverTitle>Contribution rate</PopoverTitle> <PopoverDescription> The share of the salary paid into the scheme. </PopoverDescription> </PopoverHeader> <form className="mt-3 flex items-end gap-2" onSubmit={(event) => { event.preventDefault(); setRate(draft); setOpen(false); }} > <Field> <FieldLabel htmlFor="popover-rate">Rate in %</FieldLabel> <Input id="popover-rate" inputMode="decimal" value={draft} onChange={(event) => setDraft(event.target.value)} /> </Field> <Button type="submit">Save</Button> </form> </PopoverContent> </Popover>
<Popover> <PopoverTrigger render={ <Button variant="ghost" size="icon" aria-label="About the waiting period" /> } > <InfoIcon aria-hidden /> </PopoverTrigger> <PopoverContent side="right" className="w-64"> <PopoverHeader> <PopoverTitle>Waiting period</PopoverTitle> <PopoverDescription> New employees join the scheme after two months of service. </PopoverDescription> </PopoverHeader> </PopoverContent> </Popover> </div> );}Usage#
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger,} from '@workspace/active-ui/components/primitives/popover';
<Popover> <PopoverTrigger render={<Button variant="outline" />}>Rate</PopoverTrigger> <PopoverContent> <PopoverHeader> <PopoverTitle>Contribution rate</PopoverTitle> <PopoverDescription>The share of the salary paid in.</PopoverDescription> </PopoverHeader> </PopoverContent></Popover>;Anatomy#
Popover: the open state;openandon, or uncontrolled.Open Change modal(defaultfalse) makes the page inert while it is open.Popover: the element that opens it on click;Trigger openopens it on hover as well.On Hover Popover: the panel, placed byContent side(defaultbottom),align(defaultcenter) and their offsets. It flips and shifts to stay inside the viewport. It is18remwide by default; set a width withclass.Name PopoverwithHeader PopoverandTitle Popover, which name and describe the panel.Description
What your application provides#
The content and, for a form inside it, what saving does. Close the popover after saving through the open state, as the example does.
An accessible name for an icon-only trigger.
Accessibility and keyboard#
The trigger is a button with
aria-;expanded EnterorSpaceopens the popover and moves the focus into it.Escapeand a click outside close it; the focus returns to the trigger.The panel is a
role="dialog"named by its title and described by its description.
API#
PopoverContent#
Import from @workspace/
All props come from the Base UI part this component is built on.
Props
- Type
Align- Default
'center'
How to align the popup relative to the specified side.
- Type
number | OffsetFunction - Default
0
Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.
The function takes a data object parameter with the following properties:
data.: the dimensions of the anchor element with propertiesanchor widthandheight.data.: the dimensions of the positioner element with propertiespositioner widthandheight.data.: which side of the anchor element the positioner is aligned against.side data.: how the positioner is aligned relative to the specified side.align
- Type
booleanRefObject<HTMLElement | null> (closeType) => โฆ
Determines the element to focus when the popover is closed.
false: Do not move focus.true: Move focus based on the default behavior (trigger or previously focused element).Ref: Move focus to the ref element.Object function: Called with the interaction type (mouse,touch,pen, orkeyboard). Return an element to focus,trueto use the default behavior,nullto fall back to the default behavior, orfalse/undefinedto do nothing.
- Type
booleanRefObject<HTMLElement | null> (openType) => โฆ
Determines the element to focus when the popover is opened. By default, focus moves to the first tabbable element inside the popup, except when the popover is opened by touch โ then the popup itself is focused to avoid opening the virtual keyboard.
false: Do not move focus.true: Move focus based on the default behavior (first tabbable element or popup).Ref: Move focus to the ref element.Object function: Called with the interaction type (mouse,touch,pen, orkeyboard). Return an element to focus,trueto use the default behavior,nullto fall back to the default behavior, orfalse/undefinedto do nothing.
- Type
Side- Default
'bottom'
Which side of the anchor element to align the popup against. May automatically change to avoid collisions.
- Type
number | OffsetFunction - Default
0
Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.
The function takes a data object parameter with the following properties:
data.: the dimensions of the anchor element with propertiesanchor widthandheight.data.: the dimensions of the positioner element with propertiespositioner widthandheight.data.: which side of the anchor element the positioner is aligned against.side data.: how the positioner is aligned relative to the specified side.align
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Other parts#
Popover
All props come from the Base UI part this component is built on.
Props
- Type
boolean
Whether the popover is currently open.
- Type
boolean- Default
false
Whether the popover is initially open.
To render a controlled popover, use the open prop instead.
- Type
PayloadChild Render Function<โฆ> ReactNode
The content of the popover. This can be a regular React node or a render function that receives the payload of the active trigger.
- Type
string | null
ID of the trigger that the popover is associated with. This is useful in conjunction with the default prop to create an initially open popover.
- Type
PopoverHandle<unknown>
A handle to associate the popover with a trigger. If specified, allows external triggers to control the popover's open state.
- Type
"trap-focus" | boolean - Default
false
Determines if the popover enters a modal state when open.
true: user interaction is limited to the popover: document page scroll is locked, and pointer interactions on outside elements are disabled.false: user interaction with the rest of the document is allowed.'trap-: focus is trapped inside the popover, but document page scroll is not locked and pointer interactions outside of it remain enabled.focus'
On touch devices, a true modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior.
When modal is true, focus trapping is enabled only if <Popover. is rendered inside <Popover.. It can be visually hidden with your own CSS if needed, such as Tailwind's sr- utility.
When modal is 'trap-, render <Popover. inside <Popover. so touch screen readers can escape the popup.
- Type
string | null
ID of the trigger that the popover is associated with. This is useful in conjunction with the open prop to create a controlled popover. There's no need to specify this prop when the popover is uncontrolled (that is, when the open prop is not set).
- Type
RefObject<โฆ>
A ref to imperative actions.
unmount: Ends the closing phase of the popover after an externally controlled closing animation finishes. CallpreventinUnmount On Close() onfirst, otherwise the popover completes closing on its own. Whether it leaves the DOM is decided byOpen Change keepon the portal.Mounted close: Closes the popover imperatively when called.
Events
Called by the component when something happens.
- Type
(open, eventDetails) => void
Event handler called when the popover is opened or closed.
- Type
(open: boolean) => void
Event handler called after any animations complete when the popover is opened or closed.
Takes only the props listed.
PopoverTrigger
All props come from the Base UI part this component is built on.
Props
- Type
number- Default
0
How long to wait before closing the popover that was opened on hover. Specified in milliseconds.
Requires the open prop.
- Type
number- Default
300
How long to wait before the popover may be opened on hover. Specified in milliseconds.
Requires the open prop.
- Type
PopoverHandle<unknown>
A handle to associate the trigger with a popover.
- Type
string
ID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for the popover in controlled mode (with the PopoverRoot trigger prop).
- Type
boolean- Default
false
Whether the popover should also open when the trigger is hovered.
- Type
unknown
A payload to pass to the popover when it is opened.
- Type
ComponentRender Fn<โฆ> ReactElement<โฆ>
Allows you to replace the component's HTML element with a different tag, or compose it with another component.
Accepts a React or a function that returns the element to render.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Parts that take only their elementโs attributes
Popover: the attributes of its element, with className and ref, and Base UI'sDescription renderto use your own element.Popover: the attributes of aHeader <div>, with className and ref.Popover: the attributes of its element, with className and ref, and Base UI'sTitle renderto use your own element.
This page adapts the Popover documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.