An open API service indexing awesome lists of open source software.

https://github.com/h-k-dev/angular-tree

This is a production ready data tree component. The aim is high. My first project that I did not spend just 1 weekend in :D
https://github.com/h-k-dev/angular-tree

Last synced: 6 days ago
JSON representation

This is a production ready data tree component. The aim is high. My first project that I did not spend just 1 weekend in :D

Awesome Lists containing this project

README

          

# angular-tree

[![CI/CD](https://github.com/h-k-dev/angular-tree/actions/workflows/ci.yml/badge.svg)](https://github.com/h-k-dev/angular-tree/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/%40h-k-dev%2Fangular-tree)](https://www.npmjs.com/package/@h-k-dev/angular-tree)
[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/h-k-dev/angular-tree/blob/main/LICENSE)

High-performance, headless tree component for Angular. Zoneless, signals-only, virtualized from the first row — `@angular/cdk` is the only runtime dependency.

**[▶ Live demo](https://h-k-dev.github.io/angular-tree/)** — 100k-node mode, a drag & drop rules showcase, lazy loading with error + retry, context menus, inline rename, search, dark mode. The demo's full source lives in [`projects/app`](https://github.com/h-k-dev/angular-tree/tree/main/projects/app) and doubles as the reference integration.

## Why angular-tree

- **Virtualized, always** — 100k+ nodes at 60fps (CDK virtual scroll, flat internal model, O(n) recompute). There is no non-virtualized mode: rows are fixed-height (`[itemSize]`) and their DOM is disposable by design — see [Virtualization](https://github.com/h-k-dev/angular-tree/tree/main/docs/VIRTUALIZATION.md) before building stateful row templates
- **Headless** — the tree ships no UI it doesn't own: node content, checkboxes, editors, and menu items are your templates; the tree owns behavior, ARIA, and mechanics
- **Accessor-based** — no forced node shape; describe your data with functions, never reshape it. Async accessors are lazy loading
- **Controlled** — every mutation is an intent (`moved`, `renamed`, …) that you apply to your own state; the tree never touches your data
- **Complete interaction set** — multi-select (Ctrl/Shift/checkbox cascade), drag & drop with per-node rules and copy-on-modifier, keyboard move (Ctrl+X/V), lazy loading with retry, inline rename, type-ahead, search filtering, RTL, built-in context-menu host
- **Accessible** — full APG tree keyboard map, true `aria-setsize`/`aria-posinset` at virtualized edges, roving tabindex or active-descendant, screen-reader announcements — see [Accessibility](https://github.com/h-k-dev/angular-tree/tree/main/docs/ACCESSIBILITY.md)

## Install

```bash
npm install @h-k-dev/angular-tree
```

Peer dependencies: `@angular/core|common|cdk` ≥ 21.2, `rxjs` ≥ 7.8.

## Quick start

```ts
import { Component, signal } from '@angular/core';
import {
AngularTree,
MoveEvent,
TreeNodeDef,
TreeNodeToggle,
} from '@h-k-dev/angular-tree';

interface DocNode {
id: string;
name: string;
children?: DocNode[];
}

@Component({
selector: 'app-docs',
imports: [AngularTree, TreeNodeDef, TreeNodeToggle],
templateUrl: './docs.html',
})
export class Docs {
roots = signal([/* your data */]);

// Accessors DESCRIBE your data — the tree never mutates it.
// Returning a Promise/Observable makes the node lazy.
getChildren = (node: DocNode) => node.children;
getKey = (node: DocNode) => node.id;
isFolder = (node: DocNode) => node.children != null;

// Mutations arrive as INTENTS — apply them to your own state, the tree re-renders.
applyMove({ dragIds, parentId, index }: MoveEvent) {
this.roots.update((roots) => moveNodes(roots, dragIds, parentId, index));
}
}
```

```html



{{ isExpanded ? '▾' : '▸' }}
{{ node.name }}


{{ node.name }}

```

## API at a glance

The most-used surface — the [live demo](https://h-k-dev.github.io/angular-tree/) includes a full API reference page.

| Input | Purpose |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `dataSource`, `childrenAccessor`, `expansionKey` | Your data, described by functions; async children = lazy loading |
| `itemSize` | Fixed row height in px — the virtualization contract |
| `selectedKeys`, `multi`, `checkboxSelection` | Controlled selection — `[(selectedKeys)]` two-way over keys; optional cascade |
| `searchTerm`, `searchMatch` | Filtering; matches keep their ancestor chain visible |
| `disableDrag`, `disableDrop`, `disableEdit`, `isSelectable` | Per-node behavior predicates — type rules live in your code, not the tree |
| `rowClass`, `rowStyle` | Per-node row styling accessors; `rowStyle` also reaches the group's guide |
| `childrenDeps` | Declarative lazy-cache invalidation — bind what your accessor reads |
| `expandedKeys`, `defaultExpandedKeys` | Controlled expansion — `[(expandedKeys)]` two-way; or initial-only keys |
| `loading`, `indentGuides` | Root-level loading state, clickable guide lines |

| Output | Fires when |
| --------------------------------------- | -------------------------------------------------------------------- |
| `activated` | Row clicked / Enter — your "open" action |
| `moved` | Drag or keyboard move — `dragIds`, `parentId`, `index`, `dropEffect` |
| `renamed`, `selectionChange`, `toggled` | Inline rename commit, selection set change, expand/collapse |
| `childrenLoaded` | Lazy load resolved or errored (pair with `retryChildren`) |
| `contextRequested` | Right-click / Shift+F10 — feeds the built-in menu host |

## Testing

`@h-k-dev/angular-tree/testing` ships a CDK test harness (`TreeHarness`, `TreeNodeHarness`) including a real drag-gesture simulation (`dragTo`).

## Docs

- [Theming](https://github.com/h-k-dev/angular-tree/tree/main/docs/THEMING.md) — `--tree-*` tokens, Material system-token chain, row state hooks
- [Context menus](https://github.com/h-k-dev/angular-tree/tree/main/docs/CONTEXT-MENUS.md) — built-in host, external menu systems
- [Virtualization](https://github.com/h-k-dev/angular-tree/tree/main/docs/VIRTUALIZATION.md) — sizing, autosize escape hatch
- [Accessibility](https://github.com/h-k-dev/angular-tree/tree/main/docs/ACCESSIBILITY.md) — what the tree guarantees, the one row-template rule, announcements
- [Recipes](https://github.com/h-k-dev/angular-tree/tree/main/docs/RECIPES.md) — `mat-checkbox`, loading masks, dialog refocus
- [Migration](https://github.com/h-k-dev/angular-tree/tree/main/docs/MIGRATION.md) — from PrimeNG `p-tree` / jsTree: accessor adapters, CRUD → intents, synthetic nodes, typed actions

## License

MIT