---
title: Tree
description: Trees display hierarchical data (file systems, org charts, or nested categories) with expand/collapse per branch.
---

import { meta as TreeMeta, Default } from '@/content/stories/tree';
import Canvas from '@/components/component-docs/canvas';
import Demo from '@/components/component-docs/demo';

export const config = {
	dependencies: {
		components: [Canvas, Demo],
		scripts: [
			'../../../components/component-docs/demo.script.tsx',
			'../../../components/component-docs/canvas.script.tsx',
			'../../../components/component-docs/controls.script.tsx',
		],
	},
};


# Tree

<p class="docs-lede">Trees display hierarchical data (file systems, org charts, or nested categories) with expand/collapse per branch.</p>

## Try it

<Demo of={Default} meta={TreeMeta} />

## Usage

Pass a `nodes` tree structure or compose tree items as children. Bind `value` to the selected node id.

```tsx
import { RuiTree, type RuiTreeNode } from '@ecopages/radiant-ui/tree';

const nodes: RuiTreeNode[] = [
  { id: 'src', label: 'src', children: [{ id: 'app', label: 'app.ts' }] },
];

<RuiTree nodes={nodes} value="app" label="Project files" />
```

## Custom markup

`<rui-tree>` coordinates any light-DOM tree that matches its query contract. The `RuiTree` helper stamps these targets; it is not required.

```tsx
import '@ecopages/radiant-ui/tree';

<rui-tree value="app" label="Project files">
  <ul role="tree" aria-label="Project files" aria-multiselectable="false">
    <li>
      <button type="button" role="treeitem" data-value="src" aria-expanded="true">
        src
      </button>
      <ul role="group">
        <li>
          <button type="button" role="treeitem" data-value="app">
            app.ts
          </button>
        </li>
      </ul>
    </li>
  </ul>
</rui-tree>;
```

## Node selection

<p>Bind `value` to highlight the active node. Use keyboard arrows to navigate and expand branches.</p>

## Theming

Tree maps to **semantic surface and status roles**, never Tailwind palette steps:

| Part | CSS roles |
| --- | --- |
| Surface (`rui-tree`) | `background`, `on-background`, `border`, `radius-container`, `shadow-sm` |
| Branch guides | `border` |
| Node hover | `surface` |
| Selected node | `primary-container`, `on-primary-container` |
| Node focus | `surface`, `focus-ring` |

Override at the theme layer, not in component CSS.

## API

`RuiTree` is a custom element (`<rui-tree>`) that owns selection, expansion, and roving-tabindex navigation; the `RuiTree` JSX view authors tree items from a `nodes` structure.

### Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `''` | Accessible name for the tree. |
| `value` | `string` | `''` | Selected item's `data-value` / id. |

### Light-DOM contract

| Target | Required | Host writes | Author owns |
| --- | --- | --- | --- |
| `[role="tree"]` | yes | — | root list; view sets `aria-label`, `aria-multiselectable` |
| `[role="treeitem"]` | yes | `aria-selected`, roving `tabIndex` | `data-value`, `aria-expanded` (branch nodes) |
| `data-value` | per item | — | selection identity; fallback `id` or text |
| `[role="group"]` | for branches | `hidden` | sibling after expandable treeitem |

Do not set `aria-selected` or `tabIndex` on treeitems. Nested hosts: none.

### Events

| Event | Detail | Description |
| --- | --- | --- |
| `rui-change` | `{ value: string }` | Emitted when a tree item is selected. |

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `nodes` | `RuiTreeNode[]` | | Tree structure for the `RuiTree` view. |

`RuiTreeNode` is `{ id, label, children?, expanded? }`.

### View helpers

| Component | Target stamped | Notes |
| --- | --- | --- |
| `RuiTree` | `[role="tree"]` with `data-ref="root"` | Accepts `nodes` or `children`. |

### CSS classes

Public BEM classes (documented via `@cssclass`):

| Class | Description |
| --- | --- |
| `.rui-tree` | Root list (`role="tree"`). |
| `.rui-tree__item` | List item wrapping a node. |
| `.rui-tree__node` | Node button (`role="treeitem"`). |

### Theme roles

| Part | CSS variables consumed |
| --- | --- |
| Surface | `--background`, `--on-background`, `--border`, `--radius-container`, `--shadow-control` |
| Branch guides | `--border` |
| Node hover | `--surface` |
| Selected node | `--primary-container`, `--on-primary-container` |
| Node focus | `--surface`, `--focus-ring` |

## Accessibility

- Tree exposes `role="tree"` with `role="treeitem"` children.
- Expand/collapse state is communicated with `aria-expanded`.
- Provide `label` so users know what hierarchy the tree represents.
