Skip to content

HyPopover

A non-modal overlay for contextual content, built on the Native Popover API (using popover="manual" mode) with Floating UI for automatic placement. Light dismiss (click outside, Escape key) is handled by the component itself for reliable cross-browser behavior.

Trigger Patterns

Slotted trigger (preferred): The trigger element is passed via the trigger slot, ensuring ARIA relationships work correctly across shadow DOM boundaries. The trigger automatically toggles the popover on click.

for attribute (fallback): When the trigger needs to be outside the popover element (e.g., in SSR frameworks), use the for attribute to reference a trigger element by ID. You'll need to add your own click handler to toggle the popover.

Positioning Technology

This component uses Floating UI for positioning instead of CSS Anchor Positioning. See the "Why Floating UI?" section in the component documentation for details on this architectural decision.

Popover vs Dialog

A popover is NOT a dialog. Use hy-popover for lightweight, non-modal, contextual overlays like tooltips, menus, and dropdowns. Use hy-dialog for modal interactions that require user attention and response.

Semantic Role

Unlike hy-dialog, popovers have no default ARIA role. Set the role attribute based on what the popover contains:

  • role="menu" - Action menus, context menus
  • role="listbox" - Selection dropdowns
  • role="tooltip" - Tooltips and toggletips
  • role="dialog" - Dialog-like content (prefer hy-dialog for true dialogs)
  • No role - Let content provide its own semantics (e.g., when wrapping a component that already has proper ARIA)

Accessibility Features

  • Full keyboard navigation (Escape to close)
  • Light dismiss (click outside to close)
  • ARIA live regions for screen reader announcements (opt-in)
  • Automatic ARIA relationships with trigger element:
    • For tooltips: aria-describedby (tooltip describes the trigger)
    • For other roles: aria-haspopup and aria-controls
  • Role-aware focus management:
    • Tooltips: Focus stays on trigger (tooltips are supplementary)
    • Other roles: Focus moves to popover on open, returns on close
  • High contrast mode support
  • Reduced motion support

Examples

Basic Usage (Slotted Trigger - Preferred)

html
<hy-popover>
  <button slot="trigger">Open</button>
  <p>Popover content</p>
</hy-popover>

Fallback Usage (for attribute)

html
<button id="trigger">Open</button>
<hy-popover id="my-popover" for="trigger">
  <p>Popover content</p>
</hy-popover>

<script>
  const trigger = document.getElementById('trigger');
  const popover = document.getElementById('my-popover');
  trigger.addEventListener('click', () => popover.toggle());
</script>

Placement Options

html
<hy-popover placement="top">
  <button slot="trigger">Open</button>
  Top positioned content
</hy-popover>

Without Arrow

html
<hy-popover no-arrow>
  <button slot="trigger">Open</button>
  <p>No arrow indicator</p>
</hy-popover>
html
<hy-popover role="menu" label="User actions">
  <button slot="trigger">Menu</button>
  <button role="menuitem">Edit Profile</button>
  <button role="menuitem">Settings</button>
  <button role="menuitem">Logout</button>
</hy-popover>

Tooltip Popover

html
<hy-popover role="tooltip" no-arrow>
  <span slot="trigger" tabindex="0">?</span>
  Press Enter to submit the form
</hy-popover>

Preventing Close

html
<hy-popover id="popover">
  <button slot="trigger">Open</button>
  Content
</hy-popover>
<script>
  document.getElementById('popover').addEventListener('request-hide', (e) => {
    if (hasUnsavedChanges) {
      e.preventDefault();
    }
  });
</script>

Events

  • request-show - Emitted before opening; cancelable to prevent open.
  • show - Emitted after the popover opens.
  • request-hide - Emitted before closing; cancelable to prevent close.
  • hide - Emitted after the popover closes.
  • initial-focus - Fired on show (non-tooltip role) before the autofocus discovery runs. Cancelable: call event.preventDefault() to skip the default focus and apply your own. Detail: HyInitialFocusDetail

Slots

  • trigger - The element that triggers the popover (automatically toggles on click)
  • default - The content to display inside the popover.

Methods

willUpdate()

Generates unique IDs and detects trigger element before first render to prevent update-after-update warnings.

firstUpdated()

Called after the element's first update for DOM-dependent setup.

show()

Shows the popover. Emits request-show before opening (cancelable). Emits show after opened.

hide()

Hides the popover. Emits request-hide before closing (cancelable). Emits hide after closed.

toggle()

Toggles the popover open/closed state. Emits the appropriate request event (cancelable) before toggling.

reposition()

Manually triggers a position update. Useful after content changes that affect popover size.

focus()

Sets focus on the popover element or its first focusable child.

blur()

Removes focus from the popover.

Built with Lit. Documented with VitePress.