{"id":51820518,"url":"https://github.com/h-k-dev/angular-tree","last_synced_at":"2026-07-24T14:00:37.022Z","repository":{"id":369488860,"uuid":"1289422609","full_name":"h-k-dev/angular-tree","owner":"h-k-dev","description":"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","archived":false,"fork":false,"pushed_at":"2026-07-21T10:23:08.000Z","size":708,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-21T12:11:31.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/h-k-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-04T18:22:57.000Z","updated_at":"2026-07-21T10:20:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/h-k-dev/angular-tree","commit_stats":null,"previous_names":["h-k-dev/angular-tree"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/h-k-dev/angular-tree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h-k-dev%2Fangular-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h-k-dev%2Fangular-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h-k-dev%2Fangular-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h-k-dev%2Fangular-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/h-k-dev","download_url":"https://codeload.github.com/h-k-dev/angular-tree/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/h-k-dev%2Fangular-tree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35844578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-24T02:00:07.870Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-22T05:00:25.535Z","updated_at":"2026-07-24T14:00:37.015Z","avatar_url":"https://github.com/h-k-dev.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Data Grids"],"readme":"# angular-tree\n\n[![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)\n[![npm](https://img.shields.io/npm/v/%40h-k-dev%2Fangular-tree)](https://www.npmjs.com/package/@h-k-dev/angular-tree)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/h-k-dev/angular-tree/blob/main/LICENSE)\n\nHigh-performance, headless tree component for Angular. Zoneless, signals-only, virtualized from the first row — `@angular/cdk` is the only runtime dependency.\n\n**[▶ Live demo](https://h-k-dev.github.io/angular-tree/)** — 100k-node mode, a drag \u0026 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.\n\n## Why angular-tree\n\n- **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\n- **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\n- **Accessor-based** — no forced node shape; describe your data with functions, never reshape it. Async accessors are lazy loading\n- **Controlled** — every mutation is an intent (`moved`, `renamed`, …) that you apply to your own state; the tree never touches your data\n- **Complete interaction set** — multi-select (Ctrl/Shift/checkbox cascade), drag \u0026 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\n- **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)\n\n## Install\n\n```bash\nnpm install @h-k-dev/angular-tree\n```\n\nPeer dependencies: `@angular/core|common|cdk` ≥ 21.2, `rxjs` ≥ 7.8.\n\n## Quick start\n\n```ts\nimport { Component, signal } from '@angular/core';\nimport {\n  AngularTree,\n  MoveEvent,\n  TreeNodeDef,\n  TreeNodeToggle,\n} from '@h-k-dev/angular-tree';\n\ninterface DocNode {\n  id: string;\n  name: string;\n  children?: DocNode[];\n}\n\n@Component({\n  selector: 'app-docs',\n  imports: [AngularTree, TreeNodeDef, TreeNodeToggle],\n  templateUrl: './docs.html',\n})\nexport class Docs {\n  roots = signal\u003cDocNode[]\u003e([/* your data */]);\n\n  // Accessors DESCRIBE your data — the tree never mutates it.\n  // Returning a Promise/Observable makes the node lazy.\n  getChildren = (node: DocNode) =\u003e node.children;\n  getKey = (node: DocNode) =\u003e node.id;\n  isFolder = (node: DocNode) =\u003e node.children != null;\n\n  // Mutations arrive as INTENTS — apply them to your own state, the tree re-renders.\n  applyMove({ dragIds, parentId, index }: MoveEvent\u003cDocNode\u003e) {\n    this.roots.update((roots) =\u003e moveNodes(roots, dragIds, parentId, index));\n  }\n}\n```\n\n```html\n\u003cangular-tree\n  #tree=\"angularTree\"\n  [dataSource]=\"roots()\"\n  [childrenAccessor]=\"getChildren\"\n  [expansionKey]=\"getKey\"\n  [itemSize]=\"32\"\n  (moved)=\"applyMove($event)\"\n\u003e\n  \u003c!-- folder template — `when` predicates are typed type guards --\u003e\n  \u003cng-container\n    *treeNodeDef=\"let node; when: isFolder; let isExpanded = isExpanded\"\n  \u003e\n    \u003cbutton treeNodeToggle\u003e{{ isExpanded ? '▾' : '▸' }}\u003c/button\u003e\n    \u003cspan\u003e{{ node.name }}\u003c/span\u003e\n  \u003c/ng-container\u003e\n\n  \u003c!-- leaf fallback --\u003e\n  \u003cng-template treeNodeDef let-node\u003e{{ node.name }}\u003c/ng-template\u003e\n\u003c/angular-tree\u003e\n```\n\n## API at a glance\n\nThe most-used surface — the [live demo](https://h-k-dev.github.io/angular-tree/) includes a full API reference page.\n\n| Input                                                       | Purpose                                                                       |\n| ----------------------------------------------------------- | ----------------------------------------------------------------------------- |\n| `dataSource`, `childrenAccessor`, `expansionKey`            | Your data, described by functions; async children = lazy loading              |\n| `itemSize`                                                  | Fixed row height in px — the virtualization contract                          |\n| `selectedKeys`, `multi`, `checkboxSelection`                | Controlled selection — `[(selectedKeys)]` two-way over keys; optional cascade |\n| `searchTerm`, `searchMatch`                                 | Filtering; matches keep their ancestor chain visible                          |\n| `disableDrag`, `disableDrop`, `disableEdit`, `isSelectable` | Per-node behavior predicates — type rules live in your code, not the tree     |\n| `rowClass`, `rowStyle`                                      | Per-node row styling accessors; `rowStyle` also reaches the group's guide     |\n| `childrenDeps`                                              | Declarative lazy-cache invalidation — bind what your accessor reads           |\n| `expandedKeys`, `defaultExpandedKeys`                       | Controlled expansion — `[(expandedKeys)]` two-way; or initial-only keys       |\n| `loading`, `indentGuides`                                   | Root-level loading state, clickable guide lines                               |\n\n| Output                                  | Fires when                                                           |\n| --------------------------------------- | -------------------------------------------------------------------- |\n| `activated`                             | Row clicked / Enter — your \"open\" action                             |\n| `moved`                                 | Drag or keyboard move — `dragIds`, `parentId`, `index`, `dropEffect` |\n| `renamed`, `selectionChange`, `toggled` | Inline rename commit, selection set change, expand/collapse          |\n| `childrenLoaded`                        | Lazy load resolved or errored (pair with `retryChildren`)            |\n| `contextRequested`                      | Right-click / Shift+F10 — feeds the built-in menu host               |\n\n## Testing\n\n`@h-k-dev/angular-tree/testing` ships a CDK test harness (`TreeHarness`, `TreeNodeHarness`) including a real drag-gesture simulation (`dragTo`).\n\n## Docs\n\n- [Theming](https://github.com/h-k-dev/angular-tree/tree/main/docs/THEMING.md) — `--tree-*` tokens, Material system-token chain, row state hooks\n- [Context menus](https://github.com/h-k-dev/angular-tree/tree/main/docs/CONTEXT-MENUS.md) — built-in host, external menu systems\n- [Virtualization](https://github.com/h-k-dev/angular-tree/tree/main/docs/VIRTUALIZATION.md) — sizing, autosize escape hatch\n- [Accessibility](https://github.com/h-k-dev/angular-tree/tree/main/docs/ACCESSIBILITY.md) — what the tree guarantees, the one row-template rule, announcements\n- [Recipes](https://github.com/h-k-dev/angular-tree/tree/main/docs/RECIPES.md) — `mat-checkbox`, loading masks, dialog refocus\n- [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\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh-k-dev%2Fangular-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fh-k-dev%2Fangular-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fh-k-dev%2Fangular-tree/lists"}