// preview in
saved for every page

TreeView

Shows items that nest inside each other, like folders and files or categories, so people can open a branch and pick one item. For a flat list, use a list or a menu.

Pattern WAI-ARIA Tree ViewClient componentSource ↗
minimal · light · #3fa34d
  • Getting started
    • Create an account
    • Invite your team
selectionMode

Installation

Set up Camaleo once (Installation), then import what you need. It runs on the client, because it keeps the open branches and the selection.

import { TreeView, TreeItem } from "@camaleo/react";

Anatomy

A list of items, where an item with children opens a nested group. Every part has a data-slot you can target from CSS.

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d
  • src
    • components
      • button.tsx
      • card.tsx
      • index.ts
  • package.json
  • README.md
  • Billing
    • Change your plan
    • Download invoices

Open on the current item

Open the branches that lead to the selected item with defaultExpandedValues. People see where they are without clicking, and Tab lands on that item.

  • images
    • hero-banner.png
    • avatar-default.png
    • logo-mark.svg

Several items at once

Use selectionMode="multiple" when people act on a batch, like moving files. Space adds or removes one item and keeps the others.

  • Production
    • Primary database
    • Read replica
    • Cache

Icons for the kind of item

Pass icon when items are of different kinds, like servers and databases. The icon is hidden from screen readers, so the label must say everything.

  • public1.6 MB
    • hero.webp1.2 MB
    • logo.svg8 kB
    • favicon.ico15 kB
  • package.json1.4 kB

One fact per row

Use meta for a short value, like a size or a count. Screen readers read it with the label, so keep it to a few characters.

  • app
    • page.tsx
    • layout.tsx
  • package.json

Selected: app/page.tsx

React to the selection

Click a file or press Enter on it. Control selectedValues when another part of the page shows what was picked, like an editor or a preview.

Settings
  • Account
    • Profile
    • Security

Named by its heading

Point aria-labelledby at the visible heading, so screen readers say what the tree holds. The tree is one Tab stop; arrow keys move inside it.

In context

Trees usually sit in a sidebar or a card, next to the content they open. These are whole pieces of UI you can copy, in the skin you picked.

Explorer

main
  • src
    • app
      • page.tsxmodified
      • layout.tsx
  • next.config.mjs
File explorerCard · TreeView · Badge

Categories

  • Electronics296
    • Computers200
      • Laptops142
      • Desktops58
Showing 142 products
Category filterCard · TreeView · Button

Mailboxes

  • Inbox12 unread
    • Clients9 unread
    • Suppliers3 unread
  • Sent
  • Archive
Mail foldersCard · TreeView · Badge

Guidelines

  • Electronics
    • Computers
    • Audio
DoUse a tree for items that nest.

Folders, categories and sections with subsections are what the open and close arrows are for.

  • Profile
  • Notifications
  • Security
Don’tA tree for a flat list.

With no branches, the tree adds arrow keys and announcements for nothing. Use a list, links or a menu.

  • src
    • components
      • button.tsx
      • card.tsx
DoShort labels, the path in the branches.

The branch above already says where the item is, so the label only needs its own name.

  • src
    • src/components
      • src/components/button.tsx
      • src/components/card.tsx
Don’tThe full path in every label.

Long labels get cut off on narrow screens, and screen readers repeat the same words on every row.

Props

PropTypeDefaultDescription
expandedValuesstring[]—Values of the open branches (controlled).
defaultExpandedValuesstring[][]Values of the branches open at first (uncontrolled).
onExpandedChange((values: string[]) => void)—Called with the new list when a branch opens or closes.
selectedValuesstring[]—Values of the selected items (controlled). The first one is also where Tab enters the tree.
defaultSelectedValuesstring[][]Values of the items selected at first (uncontrolled). The first one is also where Tab enters the tree.
onSelectedChange((values: string[]) => void)—Called with the new list when the selection changes.
selectionModeTreeSelectionMode"single"single selects one item, multiple several, none turns selection off.
Also accepts every prop of the underlying primitive and native attributes.
PropTypeDefaultDescription
label*ReactNode—Visible text of the row.
metaReactNode—Short value on the right, like a size or a count. It is read with the label.
iconReactNode—Icon in place of the default folder or file icon.

Every item needs a value that is unique in the whole tree, like its path: two items with the same value open and select together. TreeView also takes the attributes of <ul>, and TreeItem those of <li>.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the tree itself.

Attributes

data-selectedon tree-item and tree-item-row, while selected
data-expandedon a branch's tree-item, while open
data-valuethe item's value, on tree-item

Tokens it reads

Color

--cml-border--cml-border-control--cml-card-border--cml-card-shadow--cml-fg--cml-fg-secondary--cml-focus-offset--cml-focus-ring--cml-focus-width--cml-surface-raised

Shape & size

--cml-border-width--cml-radius-control-sm--cml-radius-popover

This component only

--cml-corner-shape--cml-tree-row-radius--cml-tree-selected-border--cml-tree-selected-fg--cml-tree-selected-shadow

Accessibility

TabMoves into the tree, on the selected item, and out of it. The whole tree is one stop.
↓ / ↑Moves to the next or previous visible item.
→Opens a closed branch. On an open branch, moves to its first child.
←Closes an open branch. On a child, moves to its parent.
Home / EndMoves to the first or last visible item.
SpaceSelects the item. With multiple selection, adds or removes it.
EnterDoes what Space does, and also opens or closes a branch.
Was this page helpful? · Edit this page on GitHub