CSS-Only Low-Level Primitive

Popover

CSS styling for native HTML popover attribute. Provides top-layer positioning, light dismiss, and keyboard support without JavaScript. This is a low-level primitive—for most use cases, prefer higher-level components like Modal, Dropdown, or Tooltip.

Consider alternatives: This is a low-level primitive. For most use cases, prefer:
  • Modal (Tier 2) - Blocking dialogs with focus trap and backdrop
  • Dropdown (Tier 3) - Action menus with keyboard navigation
  • Tooltip (Tier 3) - Accessible hints with proper ARIA
  • Bottom Drawer (Tier 3) - Mobile-friendly sheets

Example

Click outside or press Escape to close.

<button class="omni-button" popovertarget="example-popover">
  Open Popover
</button>

<div popover id="example-popover" class="omni-popover">
  <p>Click outside or press Escape to close.</p>
</div>

Capabilities

What Native Popover Provides

  • Top layer rendering (no z-index issues)
  • Light dismiss (click outside closes)
  • Escape key closes
  • Works without JavaScript
  • Smooth entrance animations

What Native Popover Does NOT Provide

  • Any semantic ARIA role
  • Focus trapping
  • Backdrop/overlay
  • Keyboard navigation within content
  • Automatic positioning relative to trigger

Variants

Position Variants

Use data-position to control animation origin. Note: This only affects the animation origin, not the actual positioning (which you must handle via CSS or JavaScript):

Position: top
Position: bottom
Position: left
Position: right
<div popover class="omni-popover" data-position="top">...</div>
<div popover class="omni-popover" data-position="bottom">...</div>
<div popover class="omni-popover" data-position="left">...</div>
<div popover class="omni-popover" data-position="right">...</div>

Size Variants

Use data-size to control width constraints:

Small popover (narrower width)
Medium popover (default width)
Large popover with more content space for longer text and additional information.
<div popover class="omni-popover" data-size="sm">Small</div>
<div popover class="omni-popover">Medium (default)</div>
<div popover class="omni-popover" data-size="lg">Large</div>

Adding ARIA Roles

Since native popover doesn't provide semantic meaning, you must add appropriate ARIA based on your content:

Interactive Content (Dialog Pattern)

<div popover class="omni-popover"
     role="dialog"
     aria-labelledby="dialog-title">
  <h3 id="dialog-title">Settings</h3>
  <!-- Interactive content -->
</div>
Important: Always add appropriate ARIA roles based on your use case:
  • role="dialog" + aria-labelledby for interactive content
  • role="menu" for action lists (but use Dropdown instead)
  • role="listbox" for selection lists (but use Combobox instead)
  • role="tooltip" for hints (but use Tooltip instead)

CSS-Only Limitations

Native Popover Constraints:
  • No automatic positioning: You must manually position the popover using CSS inset properties or JavaScript. The native API doesn't calculate optimal placement relative to the trigger button.
  • No focus management: Focus doesn't automatically move to the popover. For interactive content, add autofocus to the first focusable element.
  • No collision detection: Won't automatically reposition if it overflows viewport. Use CSS anchor positioning (where supported) or JavaScript.
  • Mobile behavior: On mobile, position variants are overridden to use top-center origin for consistency.

API Reference

Attribute Values Default Description
popover Native HTML attribute (required)
id string Unique ID referenced by popovertarget
data-position top, bottom, left, right Animation origin (not actual position)
data-size sm, md, lg md Width constraints

Trigger Button Attributes

Attribute Values Description
popovertarget ID of popover Links button to popover element
popovertargetaction toggle, show, hide Action to perform (default: toggle)

Accessibility

  • Native popover provides Escape key dismiss behavior
  • Light dismiss (click outside) built into native API
  • Rendered in top layer, avoiding z-index issues
  • Must add role attribute based on content type
  • Must add aria-labelledby or aria-label for dialogs
  • Consider adding autofocus to first interactive element
  • No focus trap—users can tab out of the popover
  • Respects prefers-reduced-motion for animations

Browser Support

Native Popover API Support:

  • Chrome/Edge 114+
  • Safari 17+
  • Firefox 125+

For older browsers, the popover will render as a regular div. Consider using a polyfill or fallback to higher-level components like Modal.

Components Used

Other OmniUI components demonstrated on this page: