EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
hooks·hook·@astryxdesign/core

useTreeFocus

Manages roving-tabindex focus and the WAI-ARIA tree keyboard model. ArrowUp/ArrowDown/Home/End roam linearly over the visible treeitems (skipping disabled ones), while ArrowRight/ArrowLeft carry tree semantics (expand/collapse, move to first-child/parent). Enter/Space activate, and printable characters trigger typeahead.

@astryxdesign/core/hooks

Signature

Call shape
useTreeFocus<T extends HTMLElement = HTMLElement>(options: UseTreeFocusOptions = {}): UseTreeFocusReturn<T>
Parameters
NameType and behavior
optionsUseTreeFocusOptions · optional
Configuration object for tree focus behavior.
options.itemSelectorstring · optional · default '[role="treeitem"]'
Selector for visible treeitems within the tree, in DOM order.
options.isItemDisabled(item: HTMLElement) => boolean · optional
Predicate for whether a treeitem is disabled and must be skipped during navigation. Defaults to reading data-tree-disabled / aria-disabled.
options.getLevel(item: HTMLElement) => number · optional
Reads the 1-based nesting level of a treeitem. Defaults to the aria-level attribute.
options.onToggleExpand(id: string) => void · optional
Called to expand/collapse the treeitem with the given id (ArrowRight on a collapsed parent, ArrowLeft on an expanded parent, Enter/Space on a parent without its own action).
options.onActivate(item: HTMLElement, id: string | undefined) => boolean | void · optional
Called when Enter/Space activates a treeitem. Return true when handled; return false/undefined to let the hook fall back to toggling expansion.
options.onActiveChange(id: string | undefined) => void · optional
Notified when the hook moves focus to a treeitem. Consumers use this to move a single roving tab stop.
options.hasRovingTabIndexboolean · optional · default false
When true, the hook owns a single roving tab stop across the visible treeitems (stamps tabindex 0/-1, repairs on mount, moves with navigation). Preserves an existing tabindex="0" seed on mount. Attach the returned handleFocus to keep the stop in sync after clicks.
options.typeaheadboolean · optional · default true
Whether typeahead (jump to next item whose text starts with the typed characters) is enabled.
Returns
NameType and behavior
treeRefReact.RefObject<HTMLElement | null>
Ref to attach to the tree container element (role="tree").
handleKeyDown(e: React.KeyboardEvent) => void
Key down handler to attach to the tree container.
handleFocus(e: React.FocusEvent) => void
Focus handler to attach to the container's onFocus. Keeps the roving tab stop in sync when hasRovingTabIndex is enabled; a no-op otherwise, so always safe to attach.
focusFirst() => void
Focus the first enabled visible treeitem.
focusLast() => void
Focus the last enabled visible treeitem.

Usage

Manages roving-tabindex focus and the WAI-ARIA tree keyboard model. ArrowUp/ArrowDown/Home/End roam linearly over the visible treeitems (skipping disabled ones), while ArrowRight/ArrowLeft carry tree semantics (expand/collapse, move to first-child/parent). Enter/Space activate, and printable characters trigger typeahead.

  • Use for hierarchical tree widgets: wire onToggleExpand to your expansion state and onActiveChange to a single roving tab stop.
  • Attach both treeRef and handleKeyDown to the role="tree" container element.
  • Use for linear lists (prefer useListFocus) or 2D grids (prefer useGridFocus); those traversals differ from a tree.