Treeview

A hierarchical list of expandable items with roving keyboard navigation. Supports single and multi-select, controlled and uncontrolled expansion and selection.

Features

  • Tree structure

  • Selection

  • State

  • Mounted collapse

  • Animation composition

  • Typeahead

  • Levels

  • State attributes

Installation

npm install @ariaui/treeview

Examples

Three playgrounds from the legacy doc: a deep hierarchy with chevrons, a repo-style file tree with Lucide icons, and a multi-select root for range and modifier selection.

Styling uses shared class strings in treeviewExampleTokens.ts; the base demo uses @heroicons/react/24/solid for chevrons.

Simple

Nested folders and leaves with chevron affordances.

Preview

No preview output yet.

live.tsxReady

Advanced

Selectable folders and files with checkboxes, icons, avatars, and row actions.

Preview

No preview output yet.

live.tsxReady

Advanced controlled

value and onValueChange drive the same advanced checkbox tree from React state.

Preview

No preview output yet.

live.tsxReady

Framer Motion

Slotted groups animated from collapsed height to measured content height.

Preview

No preview output yet.

live.tsxReady

Anatomy

tsx
import * as Treeview from "@ariaui/treeview";

export default function Example() {
  return (
    <Treeview.Root>
      <Treeview.Item>
        <Treeview.Group>
          <Treeview.Item />
        </Treeview.Group>
      </Treeview.Item>
    </Treeview.Root>
  );
}

API Reference

Root

Context provider and state owner. Manages expansion, selection, and roving focus. Renders a `<div>` and forwards all div props.

PropTypeDefault
expanded
string[]
defaultExpanded
string[][]
onExpandedChange
(expanded: string[]) => void
value
string | string[]
defaultValue
string | string[]
onValueChange
(value: string | string[]) => void
multiSelect
booleanfalse
disabled
booleanfalse
AttributeValues
role'tree'
aria-multiselectable'true' when `multiSelect` is enabled; omitted otherwise

Item

A single node in the tree. Renders a `<div>`. Items without children are leaf nodes — they are never expandable and never receive `aria-expanded`. Children are hidden when the item is collapsed. Place `Treeview.Toggle` inside the label to expand or collapse without changing selection. Nesting `Item` elements inside a `Group` inside another `Item` creates deeper tree levels.

PropTypeDefault
value*
string
label
React.ReactNode
disabled
booleanfalse
AttributeValues
role'treeitem'
aria-selected'true' when selected, 'false' otherwise
aria-expanded'true' | 'false' when item has children; omitted on leaf nodes
aria-disabled'true' when disabled; omitted otherwise
aria-levelinteger depth — 1 at root, incremented per nested Group
data-state'selected' | 'unchecked'
data-expanded'true' | 'false'
data-selectedpresent when selected
data-disabledpresent when disabled

CheckboxItem

`Item` variant for checkable tree rows. It derives checked state from `Root` selection, toggles checked state on row click, Enter, or Space, and renders a `<div>` with `role="treeitem"`. Place `Treeview.Toggle` inside the label to expand or collapse without changing checked state.

PropTypeDefault
value*
string
label
React.ReactNode
disabled
booleanfalse
AttributeValues
role'treeitem'
aria-checked'true' when all descendants are checked, 'mixed' when some descendants are checked, 'false' otherwise
aria-selected'true' when checked/selected, 'false' otherwise
aria-expanded'true' | 'false' when item has children; omitted on leaf nodes
data-state'checked' | 'unchecked' | 'indeterminate'
data-selectedpresent when checked/selected
data-disabledpresent when disabled

Toggle

Expansion control for parent item labels. Renders a `<span>`, forwards span props, and toggles the owning `Item` or `CheckboxItem` without changing selection or checked state.

AttributeValues
data-state'open' | 'closed' when the owning item has children
data-expanded'true' | 'false' when the owning item has children
data-disabledpresent when the owning item is disabled

Group

Container for child items. Increments `aria-level` for all descendant `Item` elements. Renders a `<div>` by default and can slot group props onto an animation element with `asChild`. Place a `Group` as a child of an `Item` to make that item expandable. Collapsed groups are hidden by default. Use `asChild` when an animation layer needs to measure collapsed content.

PropTypeDefault
asChild
booleanfalse
AttributeValues
role'group'
data-expanded'true' | 'false' when `asChild` is enabled
data-treeview-collapsed-branchpresent when an `asChild` group is collapsed
aria-hidden'true' when an `asChild` group is collapsed

Keyboard

ShortcutAction
Move focus to the next visible item.
Move focus to the previous visible item.
On a collapsed item with children: expand it. On an expanded item or leaf: no-op.
On an expanded item: collapse it. On a collapsed or leaf item: move focus to the parent. At root level: no-op.
HomeMove focus to the first visible item.
EndMove focus to the last visible item.
EnterIn single-select mode, expand or collapse parent items without selecting them; toggle selection on leaf items. In multi-select mode, add the focused item to the selection.
SpaceIn single-select mode, expand or collapse parent items without selecting them; toggle selection on leaf items. In multi-select mode, toggle the focused item. Shift+Space extends the range.
Ctrl+ASelect all visible items. Multi-select mode only.
A–Z/0–9Typeahead. Moves focus to the next item whose label starts with the typed character. Wraps; buffer clears after 500ms of inactivity.

Accessibility

Treeview follows the WAI-ARIA APG Tree View pattern:

  • Root renders with role="tree". When multiSelect is enabled, aria-multiselectable="true" is set automatically so assistive tech announces the selection model.

  • Each Item is a role="treeitem" with aria-level reflecting its depth. Only items that have a child Group receive aria-expanded; leaf items omit the attribute per the APG.

  • The tree uses roving tabindex — only the focused item has tabIndex={0}. Arrow keys move focus, Tab leaves the tree, and disabled items are skipped by navigation.

  • aria-selected is always present on every item to let screen readers announce selection changes consistently. aria-disabled is set on disabled items and on every item when Root is disabled.

  • Always provide an accessible name for the tree — pass aria-label or aria-labelledby on Root, especially when the tree has no visible heading.

  • Use label prop (or children) to provide visible, descriptive text for each item. Avoid icon-only items without an accompanying aria-label, and give expandable rows a visible expand/collapse affordance (e.g. a rotating chevron driven by data-expanded).

  • In single-select mode, Enter and Space expand or collapse parent items without selecting them; leaf items toggle selection. In multi-select mode, Enter adds the focused item to the selection, Space toggles it, and Ctrl+A selects every visible item — pair that with a visible selection count so users know what they have acted on.

Previous
Treegrid
Next
Upload