CngxActiveDescendant
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.
Metadata#
Host#
Relationships
Index#
Properties
Methods
Inputs
HostBindings
HostListeners
Inputs#
Whether the first non-disabled item is highlighted automatically.
falseOptional 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.
"vertical" | "horizontal"Arrow-key navigation axis. Defaults to 'vertical' (listbox/menu style).
'vertical'Whether disabled items are skipped during navigation and value lookup.
truenumber | undefinedWhen 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#
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#
Methods#
highlightByIndex(index: number)Highlight by zero-based index. Out-of-range indices are ignored.
Disabled items are rejected when skipDisabled() is true.
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.
unknowntypeaheadChar(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.
HostBindings#
| Binding | Expression |
|---|---|
[attr.aria-activedescendant] | activeId() |
HostListeners#
| Event | Handler |
|---|---|
(keydown) | keydown() |