Popovers
Floating panels anchored to a trigger button, built on the native HTML popover attribute. Showing, hiding, light-dismiss (outside click), and Escape-to-close are all handled by the browser; the l-ui--popover Stimulus controller only computes placement, flipping to the opposite side if it would overflow the viewport.
CSS-classes example
Use the l-ui-popover class directly when you need full control over markup. Pair a trigger's popovertarget attribute with a popover-attribute element.
Body content. Dismiss by pressing Esc or clicking outside.
Helper
The l_ui_popover helper renders the trigger, popover element, and Stimulus wiring for you. The block's content is the popover body. Use <% (not <%=) when calling p.trigger - the builder captures its content.
Rendered by l_ui_popover. Same markup, less boilerplate.
Placement
Pass placement: as :top, :bottom (default), :left, or :right. The popover flips to the opposite side automatically if it would overflow the viewport.
Placed above the trigger.
Placed to the right of the trigger.
Placed below the trigger.
Placed to the left of the trigger.
Alignment
Pass align: as :start (default) or :end to choose which edge of the popover flushes with the trigger on the cross axis. align: :end suits a trigger sitting at the end of a row: the popover hangs back over the trigger instead of overflowing past it.
Right edge flush with the trigger's right edge.
Open on connect
Pass open: true to open the popover as soon as its Stimulus controller connects - for example, re-opening a filter popover after a form submission re-renders the page. The controller shows and positions the popover in the same task, so it never paints unpositioned. As an auto popover it still light-dismisses as usual, so the example below is only open until you click elsewhere; reload the page to see it again.
This popover was open when the page loaded.
Menu content
For a list of actions (e.g. a "more" menu on a table row), use l-ui-popover__menu to reset the popover's padding to a full-width list, and l-ui-popover__menu-item on each link or button. Add l-ui-popover__menu-item--danger for destructive actions, and an <hr class="l-ui-popover__menu-divider"> to separate groups of items. Give an icon-only trigger an aria-label. Pair with align: :end when the trigger sits at the end of a row.
See Tables for this pattern wired up as a row action menu.
Helper options
| Option | Description |
|---|---|
id: |
DOM id for the popover element; defaults to an auto-generated id |
placement: |
:top, :bottom (default), :left, or :right. Flips automatically if it would overflow the viewport |
align: |
:start (default) or :end - which edge of the popover flushes with the trigger on the cross axis |
open: |
When true, the popover opens as soon as its Stimulus controller connects, shown and positioned in the same task so it never paints unpositioned; defaults to false |
container: |
Extra HTML attributes for the wrapping <div> (e.g. class:) |
p.trigger(**opts) |
Renders the trigger <button>; opts are merged as HTML attributes |
| block content | The block's output (anything outside p.trigger) is rendered inside l-ui-popover |
| icon-only triggers | If the trigger contains only an icon (no visible text), pass aria-label: so it has an accessible name |
CSS classes
| Class | Description |
|---|---|
l-ui-popover |
Applied to the popover-attribute element; positioned by the l-ui--popover Stimulus controller |
l-ui-popover__menu |
Full-width list wrapper for a menu of actions inside a popover |
l-ui-popover__menu-item |
Full-width action link or button inside l-ui-popover__menu |
l-ui-popover__menu-item--danger |
Danger styling for a destructive menu item |
l-ui-popover__menu-divider |
Horizontal rule separating groups of items in l-ui-popover__menu (apply to an <hr>) |