CngxRovingTabindex
projects/common/a11y/roving/roving-tabindex.directive.ts
Import#
import { CngxRovingTabindex } from '@cngx/common/a11y'
Description#
Implements the WAI-ARIA roving tabindex pattern for composite widgets.
Only the active item in the group has tabindex="0" - all others get
tabindex="-1". Arrow keys move focus within the group; Tab leaves it.
Home/End jump to first/last item.
Works for toolbars, tab lists, card grids, menu bars, and any composite widget where only one item should be in the tab order at a time.
Virtual mode
When virtualCount is set, activeIndex ranges from 0 to virtualCount - 1
instead of being bounded by contentChildren.length. Items are matched by
data-cngx-recycle-index attribute. When the target item is not in the DOM
(out of rendered range), pendingFocus is set so a wiring function like
connectRecyclerToRoving() can scroll it into view.
Horizontal toolbar
<div cngxRovingTabindex orientation="horizontal" #rv="cngxRovingTabindex">
<button cngxRovingItem>Cut</button>
<button cngxRovingItem>Copy</button>
<button cngxRovingItem>Paste</button>
</div>Vertical menu with controlled index
<ul cngxRovingTabindex orientation="vertical" [(activeIndex)]="selectedIdx">
@for (item of items(); track item.id) {
<li cngxRovingItem>{{ item.label }}</li>
}
</ul>Virtual scroll integration
<div cngxRovingTabindex orientation="vertical" [virtualCount]="recycler.ariaSetSize()">
@for (item of visibleItems(); track item.id; let i = $index) {
<div cngxRovingItem [cngxVirtualItem]="recycler" [cngxVirtualItemIndex]="recycler.start() + i">
{{ item.name }}
</div>
}
</div>Metadata#
Host#
Relationships
Index#
Properties
Outputs
HostListeners
Inputs#
Index of the currently active (focusable) item. Supports two-way [(activeIndex)] binding.
0"horizontal" | "vertical" | "both"Arrow key navigation axis. 'both' enables both horizontal and
vertical arrows. Exposed as a model so composite hosts (e.g.
CngxRadioGroup, where the keyboard axis must always be 'both'
per WAI-ARIA APG regardless of the cosmetic group orientation) can
override it from their own constructor.
'horizontal'number | undefinedTotal item count for virtual mode. When set, activeIndex ranges from 0 to
virtualCount - 1 and items are matched by data-cngx-recycle-index attribute.
When not set, standard contentChildren-based navigation is used.
Outputs#
Index of the currently active (focusable) item. Supports two-way [(activeIndex)] binding.
"horizontal" | "vertical" | "both"Arrow key navigation axis. 'both' enables both horizontal and
vertical arrows. Exposed as a model so composite hosts (e.g.
CngxRadioGroup, where the keyboard axis must always be 'both'
per WAI-ARIA APG regardless of the cosmetic group orientation) can
override it from their own constructor.
Instance Properties#
unknownIndex of the item that should receive focus but is not currently in the DOM.
Non-null when virtual navigation targets an out-of-range item.
Used by connectRecyclerToRoving() to scroll the item into view and focus it.
this.pendingFocusState.asReadonly()Methods#
Clears the pending focus target. Called by connectRecyclerToRoving()
after the item has been scrolled into view and focused.
HostListeners#
| Event | Handler |
|---|---|
(keydown) | keydown() |