esc
↑↓ navigate↵ select
Browse documentation

Accessibility

TreeKit implements the WAI-ARIA Tree View pattern, not just enough ARIA to pass a linter.

Click into the tree below and try navigating with only your keyboard — every interaction available with a mouse (expand, collapse, check, select) has a keyboard equivalent.

Engineering
Show code
<TreeKit data={data} aria-label="Organization" />

Keyboard reference

↓ / ↑Move focus to the next / previous visible row
→Expand the focused node, or move focus into its first child if already expanded
←Collapse the focused node, or move focus to its parent if already collapsed
Home / EndMove focus to the first / last visible row
SpaceToggle the checkbox (or the active/selected state, if checkboxes are hidden)
EnterActivate/select the focused node

Roving tabindex

The tree itself is a single tab stop. Tabbing in focuses the first row (or the previously-focused row, if you tabbed out and back); arrow keys then move focus within the tree without moving the browser's tab stop, exactly as the ARIA Tree View pattern specifies. Internally, exactly one row has tabindex="0" at any time and every other row has tabindex="-1".

ARIA structure

  • role="tree" on the root, with an accessible name from aria-label/aria-labelledby.
  • role="treeitem" on every row.
  • aria-expanded on any row with children (omitted on leaves, per spec).
  • aria-selected reflects the "active" row (see Selection), not checkbox state.
  • aria-disabled on disabled rows.
  • aria-level, aria-posinset, and aria-setsize so assistive tech can announce depth and position even though TreeKit renders a flattened, virtualization-friendly list rather than nested DOM groups.

Real checkboxes

Each checkbox is a genuine <input type="checkbox">, with the native indeterminate DOM property set imperatively (there is no HTML attribute for it) and aria-labelledby pointing at the row's label — screen readers announce it exactly like any other checkbox with an associated label.

Verified, not assumed

TreeKit's test suite runs every interactive state (expanded, checked, indeterminate, disabled, selected) through jest-axe as part of CI — accessibility regressions fail the build the same way a broken test does.

Reduced motion

All transitions respect prefers-reduced-motion: reduce automatically. You can also force animations off regardless of the OS setting with disableAnimations — see Animations.