Skip to main content
cngx-src documentation

CngxPopover

DirectivePrimaryv0.1.0WCAG AA

projects/common/popover/popover.directive.ts

Import#

import { CngxPopover } from '@cngx/common/popover'

Description#

Signal-driven state machine for the native Popover API.

Wraps the browser's popover attribute with reactive state, CSS-transition-aware lifecycle, and CSS Anchor Positioning. Pure state machine - contains no trigger logic, no delays.

State lifecycle: closedopeningopenclosingclosed. CSS classes cngx-popover--opening, cngx-popover--open, and cngx-popover--closing are applied to the host for transition hooks.

Declarative click popover

<button [cngxPopoverTrigger]="pop" (click)="pop.toggle()">Menu</button>
<div cngxPopover #pop="cngxPopover" placement="bottom-start">
  <menu><li>Edit</li><li>Delete</li></menu>
</div>

Controlled open state

<div cngxPopover [cngxPopoverOpen]="showErrors()" role="alert">
  {{ errorSummary() }}
</div>

https://cngxjs.github.io/cngx/examples/#/common/interactive/listbox/trigger/select-dropdown https://cngxjs.github.io/cngx/examples/#/common/popover/click-popover https://cngxjs.github.io/cngx/examples/#/common/popover/controlled-open https://cngxjs.github.io/cngx/examples/#/common/popover/escape-mode https://cngxjs.github.io/cngx/examples/#/common/popover/placement-variants

Collision recovery with <try-tactic> fallbacks

Apply CSS Anchor Positioning's position-try-fallbacks declaratively by binding the new positionTryFallbacks input. Each entry is a CSS <try-tactic> keyword (or composed pair) written verbatim into the host's position-try-fallbacks property. Mirrors the precedent in @cngx/forms/select panels.

<div cngxPopover
     placement="right-start"
     [positionTryFallbacks]="['flip-inline', 'flip-block', 'flip-block flip-inline']">
  <!-- popover content -->
</div>

When the array is empty (default), the host does not write a position-try-fallbacks style - the browser positions the popover at the declared placement regardless of viewport clipping.

Metadata#

Host#

Relationships

Index#

Inputs#

closeOnEscape#
input()

Whether Escape key dismisses the popover.

default true
closeOnOutsideClick#
input()

Whether a pointerdown outside both the popover and its anchor (trigger) dismisses it - menu / listbox light-dismiss. Opt-in (default false) so existing manual-mode popovers keep full control; the anchor is excluded so a click on the trigger toggles via the trigger's own handler instead of being closed here and immediately reopened.

default false
controlledOpen#boolean | undefined
input()

Controlled open state. When set, drives the popover reactively. undefined = uncontrolled (default).

default undefined, { alias: 'cngxPopoverOpen', }
exclusive#
input()

When true (default), opening this popover closes any other open CngxPopover instance. Set to false to allow multiple popovers open simultaneously.

default true
input()

Native popover mode. 'manual' for full control, 'auto' for browser light dismiss.

default 'manual'
offset#
input()

Gap between anchor and popover in px.

default 8
input()

Anchor-relative placement.

default 'bottom'
input()

CSS <try-tactic> fallbacks for position-try-fallbacks. Empty array (default) means the host does not write the property at all. Non-empty entries are written verbatim, comma-joined, in declaration order. Spec-compatible vocabulary only (no cngx placement tokens).

default []

Instance Properties#

anchorElement#HTMLElement | null
signal()Readonly

The anchor element for Floating UI fallback positioning. Set by CngxPopoverTrigger or CngxTooltip.

signal<HTMLElement | null>(null)
arrowOffset#unknown
Readonly

Public read-only view of the arrow's inline-axis offset (<px> or null before the first geometry read). Consumers projecting a cngxPopoverArrow template use this to render their own glyph at the same coordinate the default arrow ornament would.

this._arrowOffset.asReadonly()
elementRef#unknown
Readonly

Host ElementRef. Public for consumers that need to pass the popover's native element to APIs expecting an ElementRef (scroll observers, intersection observers, focus managers, …). Notable consumer: injectRecycler({ scrollElement: pop.elementRef }) for @cngx/forms/select virtualisation - the popover IS the scroll container when select-base.css's max-height + overflow-y rules apply.

inject<ElementRef<HTMLElement>>(ElementRef)
signal()Readonly

Hint for the CngxPopoverTrigger's aria-haspopup value. Composers such as CngxPopoverPanel write this signal so any trigger pointing at the popover defaults to the right role without the consumer having to set haspopup on every trigger element. Consumer-supplied haspopup on the trigger still wins.

signal<PopoverHaspopup | undefined>(undefined)
id#unknown
Readonly

Unique auto-generated ID for this popover instance.

this.idSignal.asReadonly()
state#unknown
Readonly

Current lifecycle state.

this.stateSignal.asReadonly()

Methods#

handleToggle#void
Protected
handleToggle(e: ToggleEvent)
@parameToggleEvent
hide#void

Close the popover. No-op if already closed or closing.

show#void

Open the popover. No-op if not closed.

toggle#void

Toggle between open and closed.

HostBindings#

BindingExpression
[attr.popover]mode()
[id]id()
[attr.aria-hidden]!isVisible()
[attr.data-arrow-placement]resolvedEdge()
[class.cngx-popover--opening]isOpening()
[class.cngx-popover--open]isOpen()
[class.cngx-popover--closing]isClosing()
[style.position-anchor]cssAnchorRef()
[style.position-try-fallbacks]cssPositionTryFallbacks()
[style.margin]cssMargin()
[style.--cngx-popover-arrow-offset]arrowOffset()

HostListeners#

EventHandler
(toggle)toggle()