Skip to content

Popover

Popover component that reveals a floating bubble card layer when the trigger is hovered or clicked.

Use when you need a floating bubble panel that opens on hover or click of a trigger — <r-popover> positions and portals its <r-content> panel and wires the accessibility for you.

Quick Start

Basic Usage

The trigger lives in the default slot; the floating content is wrapped in a nested <r-content> element.

popover
this is content
html
<r-popover style="display: inline-block;">
  <r-button>popover</r-button>
  <r-content>
    <div>this is content</div>
  </r-content>
</r-popover>

API Reference

Properties

PropertyTypeDefaultDescription
placementstring'top'Panel position relative to the trigger: top, bottom, left, right
triggerstring'hover'How the panel opens: hover or click (a click handler is always bound)
getPopupContainerIdstring''id of an element to position the panel within (read at open time; not reflected)
sheetstring''CSS injected into the component's shadow DOM

Trigger Mode trigger

hover
hover
click
click
html
<r-popover trigger="hover" style="display: inline-block;">
  <r-button>hover</r-button>
  <r-content>
    <div>hover</div>
  </r-content>
</r-popover>

<r-popover trigger="click" style="display: inline-block;">
  <r-button>click</r-button>
  <r-content>
    <div>click</div>
  </r-content>
</r-popover>

Placement placement

top
top
bottom
bottom
left
left
right
right
html
<r-popover trigger="hover" placement="top" style="display: inline-block;">
  <r-button>top</r-button>
  <r-content>
    <div>top</div>
  </r-content>
</r-popover>

<r-popover trigger="hover" placement="bottom" style="display: inline-block;">
  <r-button>bottom</r-button>
  <r-content>
    <div>bottom</div>
  </r-content>
</r-popover>

<r-popover trigger="hover" placement="left" style="display: inline-block;">
  <r-button>left</r-button>
  <r-content>
    <div>left</div>
  </r-content>
</r-popover>

<r-popover trigger="hover" placement="right" style="display: inline-block;">
  <r-button>right</r-button>
  <r-content>
    <div>right</div>
  </r-content>
</r-popover>

Slots

ComponentSlotDescription
<r-popover>(default)The trigger element plus the <r-content> wrapper
<r-content>(default)The floating panel's content; these children are portaled to document.body and shown on open

Both components expose a single unnamed default slot — there are no named slots.

Events

<r-popover> dispatches no custom events. It is driven by standard DOM interaction:

  • Open: mouseenter (when trigger includes hover), click, or pressing Enter / Space while focused.
  • Close: mouseleave (hover mode), pressing Escape, or a click elsewhere in the document.

Internally, the companion <r-content> element watches its own subtree with a MutationObserver and emits a change CustomEvent (detail: { type, value: { content, mutation } }) that the popover consumes to keep the panel in sync. This is an implementation detail rather than a public API.

Accessibility is wired automatically: the host receives tabindex="0", aria-haspopup="dialog", and an aria-expanded that toggles between "false" and "true" as the panel opens and closes.

Best Practices

  • Trigger element: Place a focusable control (e.g. <r-button>) as the trigger so keyboard open/close works.
  • Content wrapper: Always wrap panel content in <r-content> — plain children that are not inside <r-content> are not shown as the floating panel.
  • Inline sizing: The host is display: block; add style="display: inline-block;" (or place it in an inline context) so it shrinks to the trigger.
  • Placement: placement is a preference, not a guarantee — when the trigger is near a viewport edge and the preferred side lacks room, the panel automatically flips to the opposite side and shifts along the cross axis to stay on-screen. This auto-flip only applies to the default body-level positioning.
  • Scoped container: Use getPopupContainerId to anchor the panel inside a specific scroll/positioning container when the default body-level positioning is not desired — flip/shift do not apply in this mode, so choose a placement that fits the container.

Released under the MIT License.