Popover

Popover keeps compact contextual content attached to its trigger. Choose it for a filter, picker or small detail panel; choose Dropdown for a list of commands with menu semantics.

Examples

Details attached to a control

Give the panel an ariaLabel that describes its content. The interactive Button remains the one trigger and one tab stop for opening or closing the panel.

A controlled filter panel

Control open when the rest of the interface must react to a panel opening or closing. Use align="end" to keep the panel's right edge with its trigger.

When to use

Use Popover for a short, non-modal panel anchored to the control that opens it.

Reach for something else when:

  • The panel is a short list of commands — use Dropdown, which supplies menu and menuitem semantics plus roving keyboard focus.
  • The content is only a brief hover or focus hint — use Tooltip.
  • The task needs blocking focus management or a larger decision — use Dialog.

Accessibility

  • Pass an interactive, focusable trigger, such as a native <button> or Button. It receives aria-haspopup="dialog", aria-expanded, aria-controls, click handling and Enter/Space handling directly, preserving one interactive element and one tab stop.
  • The open panel is an in-flow role="dialog" named by ariaLabel; it is not portaled and is not modal, so it does not move or trap focus.
  • A mousedown outside the component closes the panel and lets focus remain where the person clicked. Escape closes it and returns focus to the trigger.
  • With side="auto", placement is measured against the trigger and panel and can flip above the trigger. top and bottom choose an explicit vertical side.

API and code

NameTypeRequiredDescription
triggerReactNodeRequiredInteractive element that opens and closes the panel. It receives the panel's keyboard and ARIA semantics directly, so pass a focusable control such as a `<button>` or `Button`.
openboolean—Whether the panel is open in controlled mode.
defaultOpenboolean—Whether the panel is initially open in uncontrolled mode. Default: `false`.
onOpenChange(open: boolean) => void—Called whenever the requested open state changes.
side'auto' | 'bottom' | 'top'—Preferred vertical side. Default: automatic placement; `"top"` and `"bottom"` keep the panel on that explicit side.
align'start' | 'end' | 'center'—Preferred horizontal alignment. Default: automatic placement; an explicit value overrides it.
widthnumber—Fixed panel width in CSS pixels.
ariaLabelstring—Accessible name for the non-modal dialog panel. Default: `"Popover"`.
childrenReactNodeRequiredContent rendered in the panel.

x-data="lyraPopover({ … })"

OptionTypeRequiredDescription
defaultOpenboolean—Whether the panel starts open. Default: `false`.
side'auto' | 'bottom' | 'top'—Preferred vertical side. Default: automatic placement.
align'start' | 'end' | 'center'—Preferred horizontal alignment. Defaults to automatic placement.
widthnumber—Fixed panel width in CSS pixels.
ariaLabelstring—Accessible name for the non-modal dialog panel. Default: `"Popover"`.

Without React, put the panel inside its positioned anchor and own toggle, outside-click and Escape behavior:

html
<span class="lyra-popover-anchor">
  <button
    class="lyra-btn lyra-btn--secondary lyra-btn--md"
    type="button"
    aria-haspopup="dialog"
    aria-expanded="true"
    aria-controls="project-details"
  >
    View details
  </button>
  <div
    class="lyra-popover lyra-popover--bottom lyra-popover--align-start"
    id="project-details"
    role="dialog"
    aria-label="Project details"
  >
    Atlas is on track for its June release.
  </div>
</span>

<lyra:popover> Generated from lyra-ds/blade v0.10.0.

The behavior comes from lyraPopover() — install @lyra-ds/alpine and see the HTML + Alpine tab.

PropDefaultRequiredExample values
defaultOpenfalse——
side'auto'——
alignnull——
widthnull——
ariaLabel'Popover'——
wrapTriggertrue——
blade
<lyra:popover side="bottom" align="start" aria-label="Usage details">
    <x-slot:trigger>Usage details</x-slot:trigger>
    <p>68% of the included API requests were used this cycle.</p>
</lyra:popover>