Popover

A floating card anchored to a trigger, holding a title, a body and anything interactive. A Tooltip is the version with neither.

Accessibility

What Popover does for you, and what it leaves to the page around it.

What it renders

The bubble is one <div role="tooltip"> with a generated id, holding one div for title and one for content. Neither is a heading element, and neither is named.
  • The trigger points at it with aria-describedby. The attribute is added to your child element, after any aria-describedby it already has.
  • It is only set while the bubble is open. A closed popover has no element to point at.
  • A description is not a dialog. The trigger keeps its own name, and the bubble is read after it as extra detail. Nothing tells a screen reader that the bubble holds controls.
  • With neither title nor content, no bubble renders and the trigger gets no aria-describedby.

Reaching it from the keyboard

  • The default hover has no keyboard route. A reader who never uses a pointer never sees the bubble.
  • Add focus to a read-only bubble whose trigger is focusable. Tabbing to the trigger then opens the bubble. It only works when there is nothing inside to operate.
  • Interactive content needs trigger="click". Enter and Space click a real button, so keyboard, pointer and touch all open the bubble the same way.
  • A trigger that cannot take focus (a plain <span>, an icon) has no keyboard route whatever trigger says. Put the popover on a real button.

Focus on open and on close

Popover does not move focus. Opening one leaves focus on the trigger, and closing one changes nothing.
  • The bubble is a portal. It renders at the end of the document, so Tab from the trigger goes to whatever follows the trigger, not into the bubble.
  • Move focus into the bubble yourself when it holds controls. Control open, focus the first field or button when it opens, and return focus to the trigger when it closes.
  • A bubble can hold one focusable thing, or a few in a row. One that needs a focus trap should be a Modal.

Dismissing it

Every way to close a popover uses the pointer. Escape does not close it.
  • Escape does nothing. Popover has no key handling at all, so this is not a setting you missed.
  • Add it with open and onOpenChange for any bubble the keyboard can open, and send focus back to the trigger in the same handler. WCAG asks content shown on hover to have a way to dismiss it without moving the pointer.
  • A click popover closes on a press outside it. That only listens for the pointer, so it does not close when a keyboard reader tabs away.
  • A hover popover stays open while the pointer is on it, so a reader using a screen magnifier can move into it. Setting mouseLeaveDelay to 0 takes that away.

Disabled triggers

  • A disabled <button> gets no pointer events and no focus, so the popover around it never opens.
  • Wrap the disabled control in a <span> with inline-block and put the popover on the span, which does get the events.
  • That only fixes the pointer. A keyboard reader still cannot focus the disabled control, so say why it is disabled somewhere else on the page too.

Contrast and motion

The default bubble follows the theme, so its contrast is the theme's. A color needs checking.
  • White text is not readable on every preset. The kit keeps white on the dark presets (blue, purple, magenta, red, geekblue) and gives the bright ones the dark end of their own color ramp, in both modes.
  • A custom CSS color is yours to check. The kit gives a light fill dark text and a dark fill white text, but the result is only as good as the color you pass.
  • Content in the bubble inherits that text color. Check a link or a Button with its own color against the bubble's fill, not the page.
  • transition={false} removes the zoom on open and close. Use it under prefers-reduced-motion, or turn motion off for the whole theme with the motion token.