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.

Exclusivity governs sibling popovers only: a popover nested inside another open popover (a select panel or submenu opening within a popover-hosted surface) is that container's child, not a rival, and never evicts its ancestor.

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#unknown
Readonly

The anchor element for Floating UI fallback positioning and the arrow-offset geometry. Registered by CngxPopoverTrigger (or a composing organism) via setAnchorElement.

this.anchorElementState.asReadonly()
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)
focusOrigin#unknown
Readonly

The element that held focus when show was entered, captured synchronously BEFORE the native showPopover() call - content autofocus inside the panel therefore cannot displace it. CngxPopoverTrigger's restoreFocus reads it as the restore target; cleared on finalize.

this.focusOriginState.asReadonly()
haspopup#unknown
Readonly

Hint for the CngxPopoverTrigger's aria-haspopup value. Composers such as CngxPopoverPanel install it via setHaspopup 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.

this.haspopupState.asReadonly()
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.

setAnchorElement#void
setAnchorElement(element: HTMLElement | null)

Register the anchor element for fallback positioning and arrow geometry, or clear it with null. Called by CngxPopoverTrigger on registration/destroy and by composing organisms that anchor a panel to a virtual element (context-menu pointer coords).

@paramelementHTMLElement | null
setHaspopup#void
setHaspopup(value: PopoverHaspopup | undefined)

Install the aria-haspopup hint triggers fall back to when the consumer sets none. Composers (CngxPopoverPanel, menu wirings) call this once at construction; undefined clears the hint.

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()