Skip to content

Tree view component

components specs/components/tree-view.kmd

Hierarchical, expandable/collapsible list for nested data — file explorers, settings navigation, nested categories, org structures — with optional tri-state cascading checkboxes, lazy child loading, and full keyboard + ARIA tree semantics. Modeled after Fluent 2 TreeView (and the WAI-ARIA tree pattern). Distinct from a flat list and from a data table.

When this spec applies

Primary triggers

All triggers

Specification body

Component — Tree view

Status: v0.1.0 — Draft. Promoted from the Microsoft Fluent 2 parity scan (meta/docs/stack #081). Sources: https://fluent2.microsoft.design/ (TreeView) + WAI-ARIA tree pattern.

R1 — When to use

Use a tree view for data with a parent→child hierarchy the user navigates by expanding nodes (files/folders, nested settings, categories). Do NOT use it for:

  • flat, same-level items → specs/components/lists.kmd;
  • tabular/columnar records → specs/components/data-table.kmd;
  • transient command lists → specs/components/menus.kmd.

R2 — Anatomy

Each node row: an expand/collapse twisty (only when it has children), depth indentation, an optional checkbox (R4), an optional icon, and the label. Leaf nodes align with their siblings (no orphan twisty).

R3 — Expand / collapse

  • Children may load lazily on first expand (show a specs/components/skeleton.kmd placeholder while loading).
  • Expansion state persists across re-render within a session; expand-all / collapse-all are optional bulk controls.
  • A node with zero children after load shows no twisty.

R4 — Cascading checkboxes (tri-state)

When selection-by-inclusion is enabled, checkboxes are tri-state:

  • checking a node checks all descendants;
  • unchecking clears all descendants;
  • a node whose descendants are mixed renders indeterminate (aria-checked="mixed");
  • a node becomes checked iff all its children are checked (state propagates up as well as down). The checked set is derived from leaves; never store a parent "checked" that contradicts its children.

R5 — Selection vs check (distinct)

  • Focus/selection = the active node (single, keyboard-navigable).
  • Check = membership in an inclusion set (R4), independent of focus. Both can coexist (you can move focus without changing checks). For pure multi-select without hierarchy semantics, see specs/interaction/selection.kmd.

R6 — Keyboard

  • ↑/↓ move focus across visible nodes; expands (or moves to first child), collapses (or moves to parent); Home/End jump to first/last; type-ahead matches labels.
  • Space toggles the focused node's checkbox; Enter activates the node's primary action.
  • Exactly one node is in the tab order (roving tabindex); arrows move within.

R7 — Scale

Virtualize rendering for large/deep trees (only expanded, on-screen nodes in the DOM). Any truncated/lazy-unloaded branch is disclosed, never silently capped.

R8 — Accessibility

  • role="tree" on the container; role="treeitem" per node; child lists wrapped in role="group".
  • Each item carries aria-expanded (when expandable), aria-selected, aria-checked (true|false|mixed for R4), and aria-level / aria-setsize / aria-posinset.
  • Indentation/twisty are not the sole structure signal — the ARIA level + group convey hierarchy to assistive tech.

Não-escopo

  • Drag-to-reorder / drag-between-nodes (separate enhancement).
  • Columnar tree-grid (a data-table variant, not this).
  • The backing data model / lazy-load transport.

References