Popover
Floating panel anchored to a trigger element for displaying rich content.
Quick Start
<%= kui(:popover) do %>
<%= kui(:popover, :trigger) do %>
<%= kui(:button, variant: :outline) { "Open Popover" } %>
<% end %>
<%= kui(:popover, :content) do %>
<%= kui(:popover, :header) do %>
<%= kui(:popover, :title) { "Title" } %>
<%= kui(:popover, :description) { "Description text here." } %>
<% end %>
<% end %>
<% end %>
Locals
Root
| Local | Type | Default |
|---|---|---|
css_classes: |
String | "" |
**component_options |
Hash | {} |
Content
| Local | Type | Default |
|---|---|---|
align: |
:start | :center | :end |
:center |
css_classes: |
String | "" |
**component_options |
Hash | {} |
Sub-parts
| Part | Usage | Purpose |
|---|---|---|
:trigger |
kui(:popover, :trigger) |
Button that opens/closes the popover |
:content |
kui(:popover, :content) |
Floating panel |
:anchor |
kui(:popover, :anchor) |
Alternate positioning reference |
:header |
kui(:popover, :header) |
Title + description wrapper |
:title |
kui(:popover, :title) |
Heading text |
:description |
kui(:popover, :description) |
Description text |
All sub-parts accept css_classes: and **component_options.
Anatomy
Popover
├── Popover Trigger
├── Popover Content
│ ├── Popover Header
│ │ ├── Popover Title
│ │ └── Popover Description
│ └── (body content)
└── Popover Anchor (optional)
Usage
Basic
A simple popover with a header, title, and description.
<%= kui(:popover) do %>
<%= kui(:popover, :trigger) do %>
<%= kui(:button, variant: :outline) { "Open Popover" } %>
<% end %>
<%= kui(:popover, :content, align: :start) do %>
<%= kui(:popover, :header) do %>
<%= kui(:popover, :title) { "Dimensions" } %>
<%= kui(:popover, :description) { "Set the dimensions for the layer." } %>
<% end %>
<% end %>
<% end %>
Align
Use the align: local on the content sub-part to control horizontal alignment
relative to the trigger. Options: :start, :center (default), :end.
<%= kui(:popover, :content, align: :start) do %>...<% end %>
<%= kui(:popover, :content, align: :center) do %>...<% end %>
<%= kui(:popover, :content, align: :end) do %>...<% end %>
With Form
Place form fields inside the popover content for inline editing.
<%= kui(:popover) do %>
<%= kui(:popover, :trigger) do %>
<%= kui(:button, variant: :outline) { "Open Popover" } %>
<% end %>
<%= kui(:popover, :content, css_classes: "w-64", align: :start) do %>
<%= kui(:popover, :header) do %>
<%= kui(:popover, :title) { "Dimensions" } %>
<%= kui(:popover, :description) { "Set the dimensions for the layer." } %>
<% end %>
<div class="mt-4 grid gap-4">
<%= kui(:field, orientation: :horizontal) do %>
<%= kui(:field, :label, for: "width", css_classes: "w-1/2") { "Width" } %>
<%= kui(:input, id: "width", value: "100%") %>
<% end %>
<%= kui(:field, orientation: :horizontal) do %>
<%= kui(:field, :label, for: "height", css_classes: "w-1/2") { "Height" } %>
<%= kui(:input, id: "height", value: "25px") %>
<% end %>
</div>
<% end %>
<% end %>
Anchor
Use the anchor sub-part to position the popover relative to a different element than the trigger.
<%= kui(:popover) do %>
<%= kui(:popover, :anchor) do %>
<div>The popover will be positioned relative to this element.</div>
<% end %>
<%= kui(:popover, :trigger) do %>
<%= kui(:button, variant: :outline) { "Open" } %>
<% end %>
<%= kui(:popover, :content) do %>
<p>Positioned relative to the anchor, not the trigger.</p>
<% end %>
<% end %>
Theme
PopoverContent = ClassVariants.build(
base: "bg-background text-foreground z-50 w-72 rounded-md " \
"ring ring-inset ring-border p-4 shadow-md outline-hidden"
)
PopoverHeader = ClassVariants.build(base: "flex flex-col gap-1 text-sm")
PopoverTitle = ClassVariants.build(base: "font-medium")
PopoverDescription = ClassVariants.build(base: "text-muted-foreground")
Stimulus Controller
The popover uses a kiso--popover Stimulus controller for:
- Toggle open/close on trigger click
- Click outside to dismiss
- Escape key to close
- Focus trap inside content when open
- Positioning relative to trigger (or anchor if present)
- Alignment control via
data-alignattribute
Register via KisoUi.start(application) or manually:
import { KisoPopoverController } from "kiso-ui"
application.register("kiso--popover", KisoPopoverController)
Accessibility
- Trigger gets
aria-haspopup="dialog"andaria-expanded(toggled by controller) - Content has
role="dialog" - Escape key closes the popover
- Focus is trapped inside the content when open
- Focus returns to trigger on close
- Click outside dismisses the popover