Popover composes a panel component and a trigger directive.

popover.ts
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 */
        },
      },
    }),
  ],
};
NameTypeDefaultDescription
placement'top' | 'bottom' | 'left' | 'right' — Preferred side of the anchor. The overlay flips to the opposite side when it does not fit.
offsetnumber — Gap in px between the anchor and the overlay panel.
align'start' | 'center' | 'end' — Alignment along the anchor edge.
arrowboolean — Shows the arrow caret pointing to the anchor.
triggerType'click' | 'hover' — Whether the popover opens on click or on hover.
hoverDelaynumber — 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.

NameTypeDefaultDescription
--kui-popover-colorCSS custom property--kui-color-textColor
--kui-popover-title-colorCSS custom property--kui-color-textTitle color
--kui-popover-desc-colorCSS custom property--kui-color-text-secondaryDesc color
NameTypeDefaultDescription
--kui-popover-title-font-sizeCSS custom property--kui-text-sm-sizeTitle font size
--kui-popover-desc-font-sizeCSS custom property--kui-text-sm-sizeDesc 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.

NameTypeDefaultDescription
labelstring — 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.

NameTypeDefaultDescription
placement'top' | 'bottom' | 'left' | 'right' | undefinedundefinedPreferred side of the anchor (defaults.popover.placement, then bottom). Auto-flips to the opposite side to fit the viewport.
align'start' | 'center' | 'end' | undefinedundefinedAlignment of the panel along the anchor edge (defaults.popover.align, then center). Preserved after a placement flip.
arrowboolean | undefinedundefinedShows the arrow caret pointing to the anchor. Falls back to defaults.popover.arrow, then false.
triggerType'click' | 'hover' | undefinedundefinedFalls 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.
ariaLabelstring | undefinedundefinedAccessible name for the role="dialog" panel. Falls back to the popover.label message (Popover); prefer content-specific text.
hoverDelaynumber | undefinedundefinedDelay in ms before closing on mouseleave in hover mode (defaults.popover.hoverDelay, then 100). Lets the mouse travel from trigger to panel.
offsetnumber | undefinedundefinedGap in px between the anchor and the panel (defaults.popover.offset, then 8). The arrow adds 6px automatically. A static numeric string is coerced.
trapFocusbooleanfalseTraps focus inside the panel and auto-focuses the first focusable element on open.
openboolean (model)falseCurrent 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-bgCSS custom propertyvar(--kui-color-surface-elevated)Panel background.
--kui-popover-borderCSS custom propertyvar(--kui-color-border)Panel border color.
--kui-popover-radiusCSS custom propertyvar(--kui-radius-lg)Panel corner radius.
--kui-popover-shadowCSS custom propertyvar(--kui-shadow-lg)Panel drop shadow.
--kui-popover-padding-xCSS custom propertyvar(--kui-space-4)Panel horizontal padding.
--kui-popover-padding-yCSS custom propertyvar(--kui-space-4)Panel vertical padding.
--kui-popover-min-widthCSS custom property160pxMinimum panel width.
--kui-popover-max-widthCSS custom property320pxMaximum panel width.
--kui-popover-arrow-sizeCSS custom property10pxArrow caret size.
--kui-z-popoverCSS custom property400Panel 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.
KuiPopoverOptionsinterface-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" with aria-label set from ariaLabel. Prefer content-specific text over the popover.label message (Popover) used when it is unset.
  • [kuiPopoverFor] sets aria-expanded and aria-haspopup="dialog" on the trigger automatically.
  • Click mode: Escape or an outside click closes the panel and returns focus to the trigger.
  • Hover mode: mouseenter on the trigger opens the panel; mouseleave starts a hoverDelay timer that a mouseenter on the panel cancels.
  • With prefers-reduced-motion the 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.md in the library repository for current review status.

Consumer-visible changes of @kikita-labs/ui 2.0 for Popover.

  • The classes are KuiPopover and KuiPopoverFor; the Component and Directive suffixes are gone.
  • Placement, offset, alignment, arrow, trigger type and hover delay defaults moved to provideKuiDefaults({ popover: { ... } }); the matching inputs are now undefined until set.
  • The default ariaLabel comes from the popover.label message.
  • Static numeric offset and hoverDelay values are coerced.
  • The panel text, title and description colours and font sizes have tokens, and --kui-z-popover only applies in browsers without the Popover API.