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 addresses the absolute index space [0, virtualCount) even when only a window is rendered. Bind windowStart to the recycler's window start so item lookups (id resolution, disabled checks, typeahead labels) map absolute indices onto the rendered subset. Targets outside the window surface as pendingHighlight; the consumer scrolls them into view (connectRecyclerToActiveDescendant) and the directive clears the pending state once the target renders.

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.

windowStart#number
input()

Absolute index of the first rendered item in virtual mode - the recycler window start. All rendered-item lookups are offset by it so absolute indices resolve the right item once the window has scrolled past 0. Ignored when virtualCount is unset.

default 0

Outputs#

activated#unknown
output()

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

output()

Emitted whenever the highlighted item changes.

typeaheadMissed#string
output()

Emitted when a typeahead query finds no match in the rendered window. Carries the resolved query term (lowercased; a repeated single letter collapses to that letter per the APG cycle rule). The rendered window is AD's whole search space - hosts whose real item space is larger (collapsed tree branches, virtualized rows outside the window) listen here to resolve the miss themselves.

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 rendered item whose value matches (via Object.is). No-op if no match. Disabled items are rejected when skipDisabled() is true. In virtual mode only the rendered window is searched; the resolved index is absolute.

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