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 menusrole="listbox"- Selection dropdownsrole="tooltip"- Tooltips and toggletipsrole="dialog"- Dialog-like content (preferhy-dialogfor 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-haspopupandaria-controls
- For tooltips:
- 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)
<hy-popover>
<button slot="trigger">Open</button>
<p>Popover content</p>
</hy-popover>Fallback Usage (for attribute)
<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
<hy-popover placement="top">
<button slot="trigger">Open</button>
Top positioned content
</hy-popover>Without Arrow
<hy-popover no-arrow>
<button slot="trigger">Open</button>
<p>No arrow indicator</p>
</hy-popover>Menu Popover
<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
<hy-popover role="tooltip" no-arrow>
<span slot="trigger" tabindex="0">?</span>
Press Enter to submit the form
</hy-popover>Preventing Close
<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: callevent.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.