Skip to content
75NeoUI

component · react

Popover

A titled panel anchored to whatever opened it, across three sizes and twelve placements, with an arrow and a modal mode.

popover

A popover is a panel attached to the thing that opened it. It is the Dialog’s anatomy on the Tooltip’s geometry: the panel holds a title, a description and a body addressed by name, and where it sits and how it moves is the popper’s.

<Popover title="Notifications" body="Everything that happened while you were away.">
  <Button>Notifications</Button>
</Popover>
<Popover title="Notifications">
  <Button>Notifications</Button>
  <template #body>Everything that happened while you were away.</template>
</Popover>

The children are the trigger, not the content. That is the rule for every component carrying the caller’s own content: the trigger is the one part a caller has to own, because it is their own element that has to carry the popover’s props, so it is what the default slot is spent on.

Which to reach for

A tooltip explains, a popover holds. If the reader has to click something inside it, or select text out of it, or read more than a line, it is a popover. If the panel is the whole task rather than a detail of the page behind it, it is a dialog.

The panel’s parts

title and description sit at the top, and the title labels the panel for a screen reader. body is everything under them. React takes body as a prop and Vue as a slot, which is the same split the Dialog makes.

close puts a button in the top corner. The title keeps out of its way on its own: the button is positioned over the panel rather than sharing a row with the title, and the recipe reserves the space when the button is there. A popover with no title would otherwise show an empty bar.

Where it sits

placement names one of the twelve sides and corners, defaulting to bottom, and offset is the gap in pixels. Ark moves the panel when the side it was asked for would put it off screen, so a placement is a preference rather than an instruction.

arrow draws a triangle pointing back at the trigger. The panel fades and scales from the edge nearest that trigger, using the Dialog’s own keyframes and the transform origin Ark writes for the placement it settled on, so nothing in the recipe branches on placement.

Getting out

dismissible is one prop over Ark’s two switches, Escape and a click outside, because a caller thinking about a panel that should not be dismissed is thinking about both at once. Turning it off leaves the close button as the only way out, so pass close with it.

<Popover title="Confirm" body="This one needs an answer." dismissible={false} close>
  <Button>Delete</Button>
</Popover>
<Popover title="Confirm" :dismissible="false" close>
  <Button>Delete</Button>
  <template #body>This one needs an answer.</template>
</Popover>

modal traps focus in the panel, blocks scrolling and hides the rest of the page from a screen reader. It is off by default, because a popover that a reader can click past is usually the point.

Slots

The same word names the recipe slot, the data-slot attribute and the key in ui.

  • base
  • positioner
  • arrow
  • arrowTip
  • title
  • description
  • body
  • closeTrigger

Variants

Read off the recipe, so these are the values that actually resolve. A Theme layer can change which one is the default; it cannot add a value.

size
smmdlg
close
truefalse
transition
truefalse

Props

Taken by both adapters, read out of the component module. The same names and the same types work in React and Vue.

ui

PopoverUI

Per-slot class overrides.

size

"sm" | "md" | "lg"

Defaults to "md"

transition

PopoverVariants["transition"]

Defaults to "true"

title

string

A heading at the top of the panel, which also labels it for a screen reader.

description

string

A quieter line under the title.

arrow

boolean

Point a small triangle back at the trigger.

Defaults to false

placement

Placement

Which side of the trigger the panel prefers.

Defaults to "bottom"

offset

number

Gap in pixels between the trigger and the panel.

Defaults to 8

dismissible

boolean

Whether Escape and a click outside close the panel.

Defaults to true

modal

boolean

Trap focus, block scrolling, and hide the rest of the page.

Defaults to false

close

boolean

Show a close button in the panel's top corner.

Defaults to false

closeIcon

ReactNode

Replaces the close button's cross.

autoFocus

boolean

Move focus into the panel when it opens.

Defaults to true

portal

boolean

Render the panel at the end of `body`.

Defaults to true

lazyMount

boolean

Wait until first open to mount the panel.

Defaults to false

unmountOnExit

boolean

Unmount the panel again on close.

Defaults to false

React only

Also takes Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "dir" | "content">, and Pick<PopoverRootProps, "open" | "defaultOpen" | "onOpenChange" | "ids">. A className among them reaches the base slot.

children

React.ReactNode

The element that opens the popover. It becomes the trigger and carries Ark's props.

body

React.ReactNode

The panel's main content, under the title and description.