useNavigation
Standalone keyboard navigation for role-based lists. Uses DOM queries to find navigable items. No provider needed.
useNavigation adds arrow-key navigation, selection, and focus tracking to any list of role-attributed elements. It is standalone — it returns an onKeyDown handler you attach to the container and needs no provider. Items are discovered from the DOM by ARIA role, so the hook stays declarative and works with whatever markup you already render.
When to use it
- Listboxes, menus, radio groups, tab bars, and command lists embedded inside a single component.
- Cases where you control the container and can attach
onKeyDowndirectly. - Copy-paste consumers that want list navigation without pulling in
KeyboardProvider.
When arrow keys should work without the user first clicking into the list, or the list is the main content of a panel that must respect a scope stack, use useScopedNavigation instead. For deeper guidance see the navigation guide.
DOM contract
Three things must hold for item discovery to work:
- A container element with a ref passed as
containerRef. - Child elements with a matching
roleattribute. - Each child carries a
data-valueattribute — the value the hook reports ashighlightedand passes toonSelect/onEnter.
Typing data-value (TValue)
The TValue generic narrows highlighted, onHighlightChange, onSelect, and onEnter to a literal union for editor convenience — but it is a type assertion, not runtime validation. Every value originates from the data-value DOM attribute and is asserted to TValue at the DOM boundary; the hook never checks that the attribute actually belongs to your union. Instantiating with useNavigation<"a" | "b"> makes TypeScript treat the values as "a" | "b", yet a stray data-value="c" is still delivered with full type confidence. Keep your data-value attributes in sync with the union you instantiate, or validate the string inside your callback before relying on it.
Installation
dgadd is not public on npm yet. Until the first release, pack @diffgazer/add from the repository and install that tarball into this app, which is what puts dgadd on pnpm exec.
The hosted registry is not public yet because r.b4r7.dev does not resolve. Use this source checkout or a local registry preview until the endpoint returns 200.
Diffgazer packages are not yet published to npm. Until the first release, pack @diffgazer/ui and @diffgazer/keys from the repository and install those tarballs.
@diffgazer/keys requires no CSS or Tailwind setup.
Parameters
Returns
Keyboard behavior
Selection mirrors ARIA semantics: Space toggles, Enter activates. On every move the hook calls scrollIntoView({ block: "nearest" }) so long lists keep the focused item visible. Custom keys can be supplied with upKeys / downKeys (for example vim-style j / k).
Examples
Basic list navigation
Horizontal tab navigation
Notes
Standalone
useNavigation does not require KeyboardProvider. It works with a direct onKeyDown handler attached to the container.
DOM-based item discovery
Navigable items are queried from the DOM using the specified role or the data-diffgazer-navigation-item data contract. Items must have a data-value attribute.
Nested collections
scopeToContainer is enabled by default so items inside a nested owner container are excluded from the parent navigation order.
Controlled and uncontrolled
Pass highlighted + onHighlightChange for controlled mode, or use defaultHighlighted for uncontrolled mode.
Edge cases
- Disabled items. With
skipDisabled(default), items exposingaria-disabled="true",data-disabled, or nativedisabledare skipped during movement. - Nested collections.
scopeToContainer(default) excludes items owned by a nested collection of the same family — an outer radiogroup ignores radios inside an inner radiogroup. - Boundaries. With
wrap: false, hitting the first or last item firesonNavigationBoundaryReached(direction, event, key)instead of wrapping — useful for moving focus to an adjacent region. moveFocus. By default the hook only updates highlight state. SetmoveFocusto also move DOM focus to the highlighted element (common forrole="tab").
Related
useScopedNavigation— the provider-backed, scope-aware counterpart.- Navigation guide — controlled vs uncontrolled, orientation, and tab patterns.
- Utilities — the DOM helpers behind item discovery.
Source
Highlighted source loads after this disclosure opens. Browse the source repository.