Overlay
Popover
A small panel of extra content or controls next to the element that opened it. The page stays usable.
Import
import { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, PopoverHeader, PopoverTitle, PopoverDescription } from "@booleanpress/ui/popover"Usage
A popover opens when its trigger is pressed and closes on Escape or a click outside. Use it for a short form, a filter, or an explanation. Use a dialog when the page must wait, and a tooltip for a label that needs no interaction.
import { Button } from "@booleanpress/ui/button"
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from "@booleanpress/ui/popover"
export function DeliveryStatus() {
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Delivery status</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Delivered</PopoverTitle>
<PopoverDescription>The mail server accepted this email.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
)
}PopoverContent is 288 px wide; set className="w-80" for another width. side and align choose the placement, and it flips to the other side when there is no room. It is uncontrolled, or controlled with open and onOpenChange. PopoverAnchor positions it against an element other than the trigger. There is no per-instance animation switch: motion is set once, in theme.css.
Examples
Basic
A heading and a sentence of explanation.
Placement
side on each of the four sides; it flips when the window has no room.
With a form
A short form inside; focus moves to the first field when it opens.
Controlled
open and onOpenChange let the content close it.
Accessibility
- Semantics
- The trigger is a
buttonwitharia-haspopup="dialog",aria-expandedandaria-controls. The content is adivwithrole="dialog". It is not modal: the page stays visible to assistive technology, and a click outside closes it. - Labels
- The trigger's text names the content. For content that is a form or a group of controls, add
aria-labeloraria-labelledbytoPopoverContent.PopoverTitleandPopoverDescriptionare plain text, not wired to the dialog. - Focus
- Focus moves into the content when it opens, Tab wraps within it while it is open, and focus returns to the trigger when it closes.
- Known limits
PopoverTitlerenders adiv, not a heading, and does not name the dialog by itself.
Keyboard
| Key | Behaviour |
|---|---|
| EnterSpace | On the trigger, opens or closes the popover. |
| Escape | Closes it and returns focus to the trigger. |
| Tab | Moves through the content, wrapping from the last element to the first; Shift+Tab goes the other way. Escape or a click outside closes it. |
API
Popover
Renders Radix Popover.Root and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | Whether it starts open, when it controls itself. | |
modal | boolean | When true, the rest of the page cannot be reached while it is open. false by default. | |
onOpenChange | ((open: boolean) => void) | Called with true or false when it opens or closes. | |
open | boolean | Whether it is open, when you control it. Pair it with onOpenChange. |
PopoverTrigger
Renders Radix Popover.Trigger and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
PopoverContent
Renders Radix Popover.Content and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "center" | "start" | "end" | Alignment along that side: start, center or end. center by default. | |
alignOffset | number | ||
arrowPadding | number | ||
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. | |
avoidCollisions | boolean | ||
collisionBoundary | Boundary | Boundary[] | ||
collisionPadding | number | Partial<Record<"left" | "right" | "top" | "bottom", number>> | ||
deferPointerDownOutside | boolean | When true, a 'pointerdown' event outside of the layered element will
wait for the interaction's click event before dispatching, allowing
third-party code to stop propagation of later events and cancel dismissal. | |
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | |
hideWhenDetached | boolean | ||
onCloseAutoFocus | ((event: Event) => void) | Event handler called when auto-focusing on close. Can be prevented. | |
onEscapeKeyDown | ((event: KeyboardEvent) => void) | Event handler called when the escape key is down. Can be prevented. | |
onFocusOutside | ((event: FocusOutsideEvent) => void) | Event handler called when the focus moves outside of the DismissableLayer.
Can be prevented. | |
onInteractOutside | ((event: FocusOutsideEvent | PointerDownOutsideEvent) => void) | Event handler called when an interaction happens outside the DismissableLayer.
Specifically, when a pointerdown event happens outside or focus moves outside of it.
Can be prevented. | |
onOpenAutoFocus | ((event: Event) => void) | Event handler called when auto-focusing on open. Can be prevented. | |
onPointerDownOutside | ((event: PointerDownOutsideEvent) => void) | Event handler called when the a pointerdown event happens outside of the DismissableLayer.
Can be prevented. | |
side | "left" | "right" | "top" | "bottom" | The preferred side: top, right, bottom or left. bottom by default; it flips when there is no room. | |
sideOffset | number | 4 | Distance in pixels from the trigger. 4 by default. |
sticky | "partial" | "always" | ||
updatePositionStrategy | "always" | "optimized" |
PopoverAnchor
Renders Radix Popover.Anchor and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. | |
virtualRef | RefObject<Measurable | null> |
PopoverHeader
Renders a div and passes it every other prop.
PopoverTitle
Renders a h2 and passes it every other prop.
PopoverDescription
Renders a p and passes it every other prop.
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="popover" (Popover), data-slot="popover-trigger" (PopoverTrigger), data-slot="popover-content" (PopoverContent), data-slot="popover-anchor" (PopoverAnchor), data-slot="popover-header" (PopoverHeader), data-slot="popover-title" (PopoverTitle), data-slot="popover-description" (PopoverDescription).
Theming
The panel is a floating surface: --popover and --popover-foreground, with the border token and a medium shadow.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--muted-foreground | text |
--popover | background |
--popover-foreground | text |