Marble UI
← Components

Tree View

Preview: Files

Hierarchical list with expand/collapse, selection and keyboard navigation (React Aria Tree).

Import

import { Tree, TreeItem } from '@marbleui/ui'

Props

<Tree>

No props of its own.

Also accepts React Aria props (100).

<TreeItem>

PropTypeDefaultDescription
title *requiredReactNode—
hideCheckboxboolean—Hide the selection checkbox that toggle-mode selection shows (e.g. single-pick menus).
iconReactNode—
metaReactNode—Right-aligned meta, e.g. a count or badge.

Also accepts React Aria props (99).

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Button · React Aria Tree · React Aria TreeItem · React Aria TreeItemContent. Follow the primitive's docs for the full keyboard map.

Usage notes

Hierarchical list with expand and collapse, optional selection and keyboard navigation (files, categories). For a flat list use ListBox; for a dropdown of nested options use TreeSelect.

<Tree aria-label="Files" selectionMode="single" defaultExpandedKeys={['src']}>
  <TreeItem id="src" title="src">
    <TreeItem id="index" title="index.ts" />
  </TreeItem>
</Tree>
  • Expansion: defaultExpandedKeys or controlled expandedKeys with onExpandedChange. Selection uses selectedKeys and onSelectionChange.
  • Give aria-label. Nest TreeItems as children; each needs an id and a title (use textValue if the title isn’t a string).
  • icon can be a node or a function of expanded; meta is right-aligned content such as a count.
  • Multiple selection shows a checkbox per item.
Example source · show
import { Tree, TreeItem } from './tree'

const Folder = (open: boolean) => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinejoin="round" aria-hidden>
    <path d={open ? 'm6 14 1.5-2.9A2 2 0 0 1 9.2 10H20a2 2 0 0 1 1.9 2.5l-1.5 6A2 2 0 0 1 18.5 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.7.9l.8 1.2a2 2 0 0 0 1.7.9H18a2 2 0 0 1 2 2v2' : 'M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.7-.9l-.8-1.2A2 2 0 0 0 7.9 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2z'} />
  </svg>
)
const File = (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinejoin="round" aria-hidden>
    <path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7zM14 2v5h6" />
  </svg>
)

export const styles = {
  Files: () => (
    <Tree aria-label="Files" className="w-72" defaultExpandedKeys={['src', 'components']} selectionMode="single" defaultSelectedKeys={['button']}>
      <TreeItem id="src" title="src" icon={Folder}>
        <TreeItem id="components" title="components" icon={Folder}>
          <TreeItem id="button" title="button.tsx" icon={File} />
          <TreeItem id="dialog" title="dialog.tsx" icon={File} />
          <TreeItem id="menu" title="menu.tsx" icon={File} />
        </TreeItem>
        <TreeItem id="lib" title="lib" icon={Folder}>
          <TreeItem id="utils" title="utils.ts" icon={File} />
        </TreeItem>
        <TreeItem id="index" title="index.ts" icon={File} />
      </TreeItem>
      <TreeItem id="pkg" title="package.json" icon={File} />
    </Tree>
  ),
  Checkboxes: () => (
    <Tree
      aria-label="Permissions"
      className="w-72"
      selectionMode="multiple"
      defaultExpandedKeys={['projects', 'billing']}
      defaultSelectedKeys={['projects-view', 'billing-view']}
    >
      <TreeItem id="projects" title="Projects" meta="3">
        <TreeItem id="projects-view" title="View" />
        <TreeItem id="projects-edit" title="Edit" />
        <TreeItem id="projects-delete" title="Delete" />
      </TreeItem>
      <TreeItem id="billing" title="Billing" meta="2">
        <TreeItem id="billing-view" title="View invoices" />
        <TreeItem id="billing-manage" title="Manage plan" />
      </TreeItem>
    </Tree>
  ),
}

Source: packages/ui/src/tree/tree.tsx

Catalog

Category
collections
Priority
Foundation
Primitive
react-aria
React Aria
Tree