Skip to main content
cngx-src documentation

CngxActiveDescendant

DirectivePrimaryv0.1.0WCAG AA

projects/common/a11y/active-descendant/active-descendant.directive.ts

Import#

import { CngxActiveDescendant } from '@cngx/common/a11y'

Description#

WAI-ARIA active-descendant pattern. Focus stays on the host; the active option is reported via aria-activedescendant.

When to use this vs. CngxRovingTabindex

  • Active-descendant when focus stays on one container (listbox, menu, combobox input) and items must not be tab-stops. Screen readers announce the referenced option while the focus ring stays on the host.
  • Roving tabindex when items themselves are tab-stops (toolbar, tab list, grid cells). See CngxRovingTabindex.

Item registration

Items register either by providing CNGX_AD_ITEM via hostDirectives / providers, or by passing a Signal<ActiveDescendantItem[]> through the items input. The items input wins when both are present; use it when items come from a dynamic data source.

Virtualization

When virtualCount is set, navigation can address indices not currently in the DOM. pendingHighlight tells the consumer to scroll the missing item into view; the consumer calls clearPendingHighlight() afterwards.

Material/CDK equivalent

Same model as cdk-listbox and mat-select, without the visual shell and driven by signals instead of ListKeyManager.

https://cngxjs.github.io/cngx/examples/#/common/a11y/active-descendant/listbox-with-items-input https://cngxjs.github.io/cngx/examples/#/common/a11y/active-descendant/typeahead

Metadata#

Host#

Relationships

Index#

Inputs#

autoHighlightFirst#boolean
input()

Whether the first non-disabled item is highlighted automatically.

default false
input()

Optional explicit item list. When provided, takes precedence over items registered via CNGX_AD_ITEM. Useful for combobox-style consumers that drive the menu from a dynamic data source - pass the unwrapped array (typically the result of a computed()), Angular's signal inputs make it reactive automatically.

input()

Whether navigation wraps from last to first and vice versa.

default true
orientation#"vertical" | "horizontal"
input()

Arrow-key navigation axis. Defaults to 'vertical' (listbox/menu style).

default 'vertical'
skipDisabled#boolean
input()

Whether disabled items are skipped during navigation and value lookup.

default true
typeahead#boolean
input()

Whether alphanumeric typeahead navigation is enabled.

default true
typeaheadDebounce#number
input()

Buffer reset window for typeahead, in milliseconds.

default 300
virtualCount#number | undefined
input()

When set, navigation treats the range [0, virtualCount) as the item space even if only a subset is rendered. Targets outside the rendered range surface as pendingHighlight for scroll-and-retry protocols.

Outputs#

activated#unknown
output()

Emitted when activateCurrent() is called with an active item.

output()

Emitted whenever the highlighted item changes.

Instance Properties#

pendingHighlight#unknown
Readonly
this.pendingHighlightState.asReadonly()

Methods#

activateCurrent#void

Emit activated with the current item's value. No-op if nothing active.

clearPendingHighlight#void

Called by recycler bridges after scrolling the pending index into view.

handleKeydown#void
Protected
handleKeydown(event: KeyboardEvent)
@parameventKeyboardEvent
highlightByIndex#void
highlightByIndex(index: number)

Highlight by zero-based index. Out-of-range indices are ignored. Disabled items are rejected when skipDisabled() is true.

@paramindexnumber
highlightByValue#void
highlightByValue(value: unknown)

Highlight the first item whose value matches (via Object.is). No-op if no match. Disabled items are rejected when skipDisabled() is true.

@paramvalueunknown
highlightFirst#void
highlightLast#void
highlightNext#void
highlightPrev#void
resetHighlight#void

Clear the highlight.

typeaheadChar#void
typeaheadChar(ch: string)

Push a printable character into the typeahead buffer and jump to the next matching option. Exposed for external keyboard hosts (e.g. a select trigger) that keep focus on themselves while using active-descendant semantics on a separate listbox.

Consumers should only forward single-character printable keys (length === 1, non-whitespace). Navigation keys and non-printables must not be forwarded.

@paramchstring

HostBindings#

BindingExpression
[attr.aria-activedescendant]activeId()

HostListeners#

EventHandler
(keydown)keydown()