Popover
Floating content panel anchored to a trigger element. Unlike Tooltip, Popover supports interactive content and both click and hover triggers. Unlike Dropdown, Popover is a free-content slot with no listbox structure.
Popover composes a panel component and a trigger directive.
import { KuiButton, KuiPopover, KuiPopoverFor } from '@kikita-labs/ui';Wire any element as a trigger with [kuiPopoverFor], then project arbitrary content into the panel.
<div class="basic-popover-example">
<button [kuiPopoverFor]="myPop" kuiButton type="button">Open</button>
<kui-popover #myPop placement="bottom" [arrow]="true" ariaLabel="Details">
<div class="kui-popover-title">Title</div>
<div class="kui-popover-desc">Supporting text.</div>
</kui-popover>
</div>Projected content is developer-provided, including buttons that call the popover's own close() method.
<div class="action-popover-example">
<button [kuiPopoverFor]="confirmPop" kuiButton type="button" appearance="danger">Delete</button>
<kui-popover
#confirmPop
placement="bottom"
align="start"
[arrow]="true"
ariaLabel="Delete record"
>
<div class="kui-popover-title">Delete record?</div>
<div class="kui-popover-desc" style="margin-bottom: 12px">This cannot be undone.</div>
<div style="display: flex; gap: 8px; justify-content: flex-end">
<button kuiButton type="button" shape="outline" size="sm" (click)="confirmPop.close()">
Cancel
</button>
<button
kuiButton
type="button"
appearance="danger"
size="sm"
(click)="delete(); confirmPop.close()"
>
Delete
</button>
</div>
</kui-popover>
@if (deleted()) {
<span class="action-popover-example__status">Record deleted.</span>
}
</div>triggerType="hover" opens on mouseenter and closes after hoverDelay, so the mouse can travel from trigger to panel.
<div class="hover-popover-example">
<button [kuiPopoverFor]="hoverPop" kuiButton type="button">Hover me</button>
<kui-popover
#hoverPop
placement="top"
triggerType="hover"
[arrow]="true"
ariaLabel="Hover details"
>
<div class="kui-popover-desc">Opens on hover. Mouse can travel to the panel.</div>
</kui-popover>
</div>Set defaults.popover once for the application or for a subtree. Each option resolves as local input > defaults.popover.<option> > built-in default.
import { provideKikitaUi } from '@kikita-labs/ui';
export const appConfig: ApplicationConfig = {
providers: [
provideKikitaUi({
defaults: {
popover: {
/* options below */
},
},
}),
],
};| Name | Type | Default | Description |
|---|---|---|---|
| placement | 'top' | 'bottom' | 'left' | 'right' | — | Preferred side of the anchor. The overlay flips to the opposite side when it does not fit. |
| offset | number | — | Gap in px between the anchor and the overlay panel. |
| align | 'start' | 'center' | 'end' | — | Alignment along the anchor edge. |
| arrow | boolean | — | Shows the arrow caret pointing to the anchor. |
| triggerType | 'click' | 'hover' | — | Whether the popover opens on click or on hover. |
| hoverDelay | number | — | Delay in ms before a hover popover closes after the pointer leaves. |
Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-popover-color | CSS custom property | --kui-color-text | Color |
| --kui-popover-title-color | CSS custom property | --kui-color-text | Title color |
| --kui-popover-desc-color | CSS custom property | --kui-color-text-secondary | Desc color |
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-popover-title-font-size | CSS custom property | --kui-text-sm-size | Title font size |
| --kui-popover-desc-font-size | CSS custom property | --kui-text-sm-size | Desc font size |
Every text the component owns (accessible names, visible words, announcements) is a typed message with an English default. Override it for the application with provideKikitaUi({ messages }), or for a subtree with provideKuiMessages.
| Name | Type | Default | Description |
|---|---|---|---|
| label | string | — | Accessible name of the panel when ariaLabel is not set. Default Popover. |
Inputs verified against @kikita-labs/ui v2.0.0 v2.0.0 public typings.
| Name | Type | Default | Description |
|---|---|---|---|
| placement | 'top' | 'bottom' | 'left' | 'right' | undefined | undefined | Preferred side of the anchor (defaults.popover.placement, then bottom). Auto-flips to the opposite side to fit the viewport. |
| align | 'start' | 'center' | 'end' | undefined | undefined | Alignment of the panel along the anchor edge (defaults.popover.align, then center). Preserved after a placement flip. |
| arrow | boolean | undefined | undefined | Shows the arrow caret pointing to the anchor. Falls back to defaults.popover.arrow, then false. |
| triggerType | 'click' | 'hover' | undefined | undefined | Falls back to defaults.popover.triggerType, then click. click toggles the panel on click and closes on outside click or ESC. hover opens on mouseenter and closes on mouseleave. |
| ariaLabel | string | undefined | undefined | Accessible name for the role="dialog" panel. Falls back to the popover.label message (Popover); prefer content-specific text. |
| hoverDelay | number | undefined | undefined | Delay in ms before closing on mouseleave in hover mode (defaults.popover.hoverDelay, then 100). Lets the mouse travel from trigger to panel. |
| offset | number | undefined | undefined | Gap in px between the anchor and the panel (defaults.popover.offset, then 8). The arrow adds 6px automatically. A static numeric string is coerced. |
| trapFocus | boolean | false | Traps focus inside the panel and auto-focuses the first focusable element on open. |
| open | boolean (model) | false | Current open state exposed for trigger integrations via openChange. Not intended as a standalone controlled API. |
| [kuiPopoverFor] | KuiPopover | undefined | - | Wires any element as a trigger for a kui-popover. Sets aria-expanded and aria-haspopup="dialog" automatically. |
| .kui-popover-title | - | - | Optional CSS class for a semi-bold sm title inside the projected content. |
| .kui-popover-desc | - | - | Optional CSS class for secondary sm supporting text inside the projected content. |
| --kui-popover-bg | CSS custom property | var(--kui-color-surface-elevated) | Panel background. |
| --kui-popover-border | CSS custom property | var(--kui-color-border) | Panel border color. |
| --kui-popover-radius | CSS custom property | var(--kui-radius-lg) | Panel corner radius. |
| --kui-popover-shadow | CSS custom property | var(--kui-shadow-lg) | Panel drop shadow. |
| --kui-popover-padding-x | CSS custom property | var(--kui-space-4) | Panel horizontal padding. |
| --kui-popover-padding-y | CSS custom property | var(--kui-space-4) | Panel vertical padding. |
| --kui-popover-min-width | CSS custom property | 160px | Minimum panel width. |
| --kui-popover-max-width | CSS custom property | 320px | Maximum panel width. |
| --kui-popover-arrow-size | CSS custom property | 10px | Arrow caret size. |
| --kui-z-popover | CSS custom property | 400 | Panel z-index in browsers without the Popover API. |
| openFor(anchor) | (anchor: Element) => void | - | Opens the popover anchored to the given element. |
| toggleFor(anchor) | (anchor: Element) => void | - | Toggles the popover for a trigger and reopens immediately when an exit animation is running. |
| close() | () => void | - | Closes the popover with the exit animation. |
| scheduleClose(delay) | (delay: number) => void | - | Schedules a close after delay ms (hover mode). |
| cancelClose() | () => void | - | Cancels a pending scheduled close. |
| KuiPopoverOptions | interface | - | Shape of defaults.popover: placement, offset, align, arrow, triggerType and hoverDelay. |
Popover exposes dialog semantics and returns focus to the trigger on close.
- The panel renders
role="dialog"witharia-labelset fromariaLabel. Prefer content-specific text over thepopover.labelmessage (Popover) used when it is unset. [kuiPopoverFor]setsaria-expandedandaria-haspopup="dialog"on the trigger automatically.- Click mode:
Escapeor an outside click closes the panel and returns focus to the trigger. - Hover mode:
mouseenteron the trigger opens the panel;mouseleavestarts ahoverDelaytimer that a mouseenter on the panel cancels. - With
prefers-reduced-motionthe panel animates opacity only, with no slide. - Set
[trapFocus]="true"when the panel contains a form or multiple interactive elements that need focus contained inside the panel while open. - Popover covers keyboard dismissal, ARIA dialog semantics, and focus return. Full screen reader and other assistive-technology verification has not been completed for this primitive yet; see
state-coverage.mdin the library repository for current review status.
Consumer-visible changes of @kikita-labs/ui 2.0 for Popover.
- The classes are
KuiPopoverandKuiPopoverFor; theComponentandDirectivesuffixes are gone. - Placement, offset, alignment, arrow, trigger type and hover delay defaults moved to
provideKuiDefaults({ popover: { ... } }); the matching inputs are nowundefineduntil set. - The default
ariaLabelcomes from thepopover.labelmessage. - Static numeric
offsetandhoverDelayvalues are coerced. - The panel text, title and description colours and font sizes have tokens, and
--kui-z-popoveronly applies in browsers without the Popover API.