Installation
Theme
Mode

Data display

Tree

Hierarchical structure for nested data — workspaces, folders, and documents. Every row is a disclosure chevron, a type icon, a label, and a child count; indentation plus hairline guides make depth legible at a glance. Full WAI-ARIA tree keyboard navigation, with expansion and selection each controlled or uncontrolled.

$npx shadcn@latest add @orbit/tree

Overview

A live tree with the header chrome: title, total item count, and expand-all / collapse-all actions. Click a row to select it (containers also toggle), or click just the chevron to toggle without selecting.

Project structure23 items
  • Orbit Workspace3
    • Product2
      • Roadmap2
        • Q3 Planning
        • Q4 Planning
    • Design2
      • Design System2
        • Components
        • Foundations
  • Marketing1
    • Campaigns2
      • Q3 Launch
      • Social Calendar

Anatomy

Three node types: an accent chip marks a workspace (space), a filled folder a container — its fill tints while open — and a sheet a leaf document. The chevron rotates 90° on expand, labels truncate with ellipsis, and a mono count sits right on containers. Selected rows tint with the brand soft.

space · folder · doc — with a selected container row
Node types6 items
  • Orbit Workspace2
    • Roadmap2
      • Q3 Planning
      • Q4 Planning

Tweaks

Two boolean props tune density without touching behavior: showCounts drops the mono child counts, connectingLines removes the hairline depth guides. Each instance below is independently live.

Counts hiddenshowCounts=false
Files23 items
  • Orbit Workspace
    • Product
      • Roadmap
        • Q3 Planning
        • Q4 Planning
    • Design
      • Design System
        • Components
        • Foundations
  • Marketing
    • Campaigns
      • Q3 Launch
      • Social Calendar
No guide linesconnectingLines=false
Workspace23 items
  • Orbit Workspace3
    • Product2
      • Roadmap2
        • Q3 Planning
        • Q4 Planning
    • Design2
      • Design System2
        • Components
        • Foundations
  • Marketing1
    • Campaigns2
      • Q3 Launch
      • Social Calendar

Controlled

Pass expandedIds / selectedId with their change callbacks to own the state — drive the tree from a router, a search field, or external buttons. Leave them off (or use the default* props) and the tree manages itself.

selected: Product · expanded: 2
Project structure23 items
  • Orbit Workspace3
    • Product2

Props

PropTypeDefaultDescription
itemsTreeItem[]Nested nodes: { id, label, type?, children? }. type is "space" | "folder" | "doc"; defaults to folder for nodes with children, doc otherwise.
titlestring"Project structure"Header title; also labels the tree for assistive tech.
showCountsbooleantrueMono child-count on container rows.
connectingLinesbooleantrueHairline depth guides on nested rows.
expandedIdsstring[]Controlled expanded container ids; pair with onExpandedChange.
defaultExpandedIdsstring[][]Containers that start expanded (uncontrolled).
onExpandedChange(ids: string[]) => voidFires on any expand / collapse, including the header expand-all and collapse-all buttons.
selectedIdstring | nullControlled selected node id; pair with onSelect.
defaultSelectedIdstring | nullnullInitially selected node (uncontrolled).
onSelect(id, item) => voidCalled when a node is selected by click, Enter, or Space.
…restHTMLAttributesEverything else is forwarded to the root <div>, including ref.

Usage

Do

Use it for real hierarchy

Nested folders, org charts, doc trees — anywhere parent/child is the point. Depth carries meaning here.

Don’t

Nest more than a few deep

Past four or five levels the indentation eats the row. Flatten, or split into linked trees.

Do

Show counts on containers

A child count tells you what’s collapsed without opening it — cheap orientation for big trees.

Don’t

Use it for a flat list

No nesting means no tree. A table or list is lighter and more scannable for single-level data.

Keyboard & accessibility

The list uses the WAI-ARIA tree pattern: role=tree on the list, treeitem rows with aria-expanded, aria-selected, and aria-level, children in role=group, and a roving tabindex so the tree is one Tab stop. Focus shows the 3px themed ring.

↑ / ↓Move focus to the previous / next visible node
Expand a closed container; then move into its first child
Collapse an open container; else jump to the parent
Home / EndJump to the first / last visible node
Enter / SpaceSelect the focused node
ClickSelect a node — and toggle it if it has children
Tab into the tree, then drive it with the arrow keys
Try the keys6 items
  • Orbit Workspace2