{"id":18320569,"url":"https://github.com/lukasbach/headless-tree","last_synced_at":"2026-01-20T16:02:29.710Z","repository":{"id":183113899,"uuid":"635059108","full_name":"lukasbach/headless-tree","owner":"lukasbach","description":"The definitive tree component for the Web","archived":false,"fork":false,"pushed_at":"2026-01-10T15:29:39.000Z","size":4224,"stargazers_count":732,"open_issues_count":23,"forks_count":26,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-01-11T04:43:56.957Z","etag":null,"topics":["a11y","accessibility","dnd","drag-and-drop","hotkeys","library","react","search","tree","ui"],"latest_commit_sha":null,"homepage":"https://headless-tree.lukasbach.com/","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/lukasbach.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"lukasbach"}},"created_at":"2023-05-01T21:54:49.000Z","updated_at":"2026-01-10T15:28:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"da5ddb8f-ffc7-4ddb-a47e-4c97bd74b7a6","html_url":"https://github.com/lukasbach/headless-tree","commit_stats":{"total_commits":281,"total_committers":3,"mean_commits":93.66666666666667,"dds":0.03558718861209964,"last_synced_commit":"e983097ee86a170e82087a07a1544e9aaaf3971a"},"previous_names":["lukasbach/headless-tree"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/lukasbach/headless-tree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukasbach%2Fheadless-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukasbach%2Fheadless-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukasbach%2Fheadless-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukasbach%2Fheadless-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukasbach","download_url":"https://codeload.github.com/lukasbach/headless-tree/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukasbach%2Fheadless-tree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28606299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T14:45:23.139Z","status":"ssl_error","status_checked_at":"2026-01-20T14:44:16.929Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["a11y","accessibility","dnd","drag-and-drop","hotkeys","library","react","search","tree","ui"],"created_at":"2024-11-05T18:16:43.831Z","updated_at":"2026-01-20T16:02:29.704Z","avatar_url":"https://github.com/lukasbach.png","language":"TypeScript","readme":"![Headless Tree](https://github.com/lukasbach/headless-tree/raw/main/packages/docs/static/img/banner-github.png)\n\n[![Documentation](https://img.shields.io/badge/docs-1e1f22?style=flat)](https://headless-tree.lukasbach.com/)\n[![Chat on Discord](https://img.shields.io/badge/discord-4c57d9?style=flat\u0026logo=discord\u0026logoColor=ffffff)](https://discord.gg/KuZ6EezzVw)\n[![Follow on Bluesky](https://img.shields.io/badge/bluesky-0285FF?style=flat\u0026logo=bluesky\u0026logoColor=ffffff)](https://bsky.app/profile/lukasbach.bsky.social)\n[![Follow on X](https://img.shields.io/badge/x-000000?style=flat\u0026logo=x\u0026logoColor=ffffff)](https://x.com/lukasmbach)\n[![Support on Github Sponsors](https://img.shields.io/badge/sponsor-EA4AAA?style=flat\u0026logo=githubsponsors\u0026logoColor=ffffff)](https://github.com/sponsors/lukasbach)\n[![Follow on Github](https://img.shields.io/badge/follow-181717?style=flat\u0026logo=github\u0026logoColor=ffffff)](https://github.com/lukasbach)\n[![NPM Core package](https://img.shields.io/badge/core-CB3837?style=flat\u0026logo=npm\u0026logoColor=ffffff)](https://www.npmjs.com/package/@headless-tree/core)\n[![NPM React package](https://img.shields.io/badge/react-CB3837?style=flat\u0026logo=npm\u0026logoColor=ffffff)](https://www.npmjs.com/package/@headless-tree/react)\n\nSuper-easy integration of complex tree components into React. Supports ordered\nand unordered drag-and-drop, extensive keybindings, search, renaming and more.\nFully customizable and accessible. Headless Tree is the official successor for\n[react-complex-tree](https://github.com/lukasbach/react-complex-tree).\n\nIt aims to bring the many features of complex tree views, like multi-select,\ndrag-and-drop, keyboard navigation, tree search, renaming and more, while\nbeing unopinionated about the styling and rendering of the tree itself.\nAccessibility is ensured by default, and the integration is extremely\nsimple and flexible.\n\nThe interface gives you a flat list of tree nodes\nthat you can easily render yourself, which keeps the complexity of the\ncode low and allows you to customize the tree to your needs. This flat\nstructure also allows you to virtualize the tree with any virtualization\nlibrary you want. The library automatically provides the necessary\naria tags to emulate a nested tree structure, so that accessibility\nrequirements are met despite the flat structure.\n\nDive into [the Get Started page](https://headless-tree.lukasbach.com/getstarted)\nto find out how to use Headless Tree, or have a look at\n[the samples on the Headless Tree Homepage](https://headless-tree.lukasbach.com/#demogrid)\nto get an idea of what you can do with it.\n\n\u003e [!TIP]  \n\u003e Headless Tree is now available as Beta! The library is mostly stable and\n\u003e production ready, and will be generally released within two months, once\n\u003e I have collected feedback and fixed any bugs that might arise. I've written\n\u003e [a blog post](https://medium.com/@lukasbach/headless-tree-and-the-future-of-react-complex-tree-fc920700e82a)\n\u003e about the details of the change, and the future of the library.\n\u003e\n\u003e Join\n\u003e [the Discord](https://discord.gg/KuZ6EezzVw) to get involved, and\n\u003e [follow on Bluesky](https://bsky.app/profile/lukasbach.bsky.social) to\n\u003e stay up to date.\n\n## Features\n\n- [Simple Interface](https://headless-tree.lukasbach.com/?demo=0#demogrid): Easy integration in React with full customizability of DOM\n- [Drag and Drop](https://headless-tree.lukasbach.com/?demo=1#demogrid): Powerful ordered drag-and-drop, that can interact with external drag events\n- [Scalable](https://headless-tree.lukasbach.com/?demo=2#demogrid): Headless Tree remains performant even with large trees\n- [Virtualization Support](https://headless-tree.lukasbach.com/?demo=3#demogrid): Compatible with common virtualization library to support 100k+ items\n- [Hotkeys!](https://headless-tree.lukasbach.com/?demo=4#demogrid): Lots of hotkeys, fully customizable\n- [Search Support](https://headless-tree.lukasbach.com/?demo=5#demogrid): Typeahead anywhere in the tree to quickly search the entire tree\n- [Rename items](https://headless-tree.lukasbach.com/?demo=6#demogrid): Optionally allow users to rename items inside the tree\n- [Manage State](https://headless-tree.lukasbach.com/?demo=7#demogrid): Let Headless Tree manage tree state internally, or manage any part of it yourself\n- [Customize Behavior](https://headless-tree.lukasbach.com/?demo=8#demogrid): Easily overwrite internal behavior like requiring double clicks on items to expand\n- [Customize Logic](https://headless-tree.lukasbach.com/?demo=9#demogrid): Overwrite or expand any internal behavior of Headless Tree\n- [Async Data Support](https://headless-tree.lukasbach.com/?demo=10#demogrid): Use synchronous or asynchronous data sources for your tree. Headless Tree comes with optional caching for async data\n- Free of dependencies\n- Or check out [this comprehensive playground](https://headless-tree.lukasbach.com/?demo=11#demogrid) that has most of the capabilities enabled.\n\n## Bundle Size\n\nHeadless Tree exports individual features in a tree-shaking-friendly\nway, allowing you to only include what you need to keep your bundle size\nsmall. Listed bundle sizes are based on min+gzipped bundles, and are\nbased on the Bundlephobia report as of Headless Tree v0.0.15.\n\n| Feature                | Bundle Size |\n|------------------------|-------------|\n| Tree Core              | 3.1kB       |\n| Sync Data Loader       | 0.8kB       |\n| Async Data Loader      | 1.4kB       |\n| Selections             | 1.1kB       |\n| Drag and Drop          | 2.8kB       |\n| Keyboard Drag and Drop | 2.7kB       |\n| Hotkeys                | 0.8kB       |\n| Tree Search            | 1.3kB       |\n| Renaming               | 0.9kB       |\n| Expand All             | 0.7kB       |\n| React Bindings         | 0.4kB       |\n\nTotal bundle size is 9.5kB plus 0.4kB for the React bindings. Note that\nthe sum of features is bigger than the total bundle size, because several\nfeatures share code. Tree-shaking will ensure that the minimum amount of\ncode is included in your bundle.\n\n## Get Started\n\n\u003e [!TIP]  \n\u003e You can find a comprehensive [get-started guide](https://headless-tree.lukasbach.com/getstarted)\n\u003e on the documentation homepage. The following gives a brief overview.\n\nInstall Headless Tree via npm:\n\n```bash\nnpm install @headless-tree/core @headless-tree/react\n```\n\nIn your react component, call the `useTree` hook from `@headless-tree/react` with the configuration of\nyour tree:\n\n```tsx\nimport {\n  hotkeysCoreFeature,\n  selectionFeature,\n  syncDataLoaderFeature,\n} from \"@headless-tree/core\";\nimport { useTree } from \"@headless-tree/react\";\n\nconst tree = useTree\u003cstring\u003e({\n  initialState: { expandedItems: [\"folder-1\"] },\n  rootItemId: \"folder\",\n  getItemName: (item) =\u003e item.getItemData(),\n  isItemFolder: (item) =\u003e !item.getItemData().endsWith(\"item\"),\n  dataLoader: {\n    getItem: (itemId) =\u003e itemId,\n    getChildren: (itemId) =\u003e [\n      `${itemId}-folder`,\n      `${itemId}-1-item`,\n      `${itemId}-2-item`,\n    ],\n  },\n  indent: 20,\n  features: [syncDataLoaderFeature, selectionFeature, hotkeysCoreFeature],\n});\n```\n\nThen, render your tree based on the tree instance returned from the hook:\n\n```tsx\n\u003cdiv {...tree.getContainerProps()} className=\"tree\"\u003e\n  {tree.getItems().map((item) =\u003e (\n    \u003cbutton\n      {...item.getProps()}\n      key={item.getId()}\n      style={{ paddingLeft: `${item.getItemMeta().level * 20}px` }}\n    \u003e\n      \u003cdiv\n        className={cn(\"treeitem\", {\n          focused: item.isFocused(),\n          expanded: item.isExpanded(),\n          selected: item.isSelected(),\n          folder: item.isFolder(),\n        })}\n      \u003e\n        {item.getItemName()}\n      \u003c/div\u003e\n    \u003c/button\u003e\n  ))}\n\u003c/div\u003e\n```\n\nRead on in the [get started guide](https://headless-tree.lukasbach.com/getstarted) to learn more about\nhow to use Headless Tree, and how to customize it to your needs.\n","funding_links":["https://github.com/sponsors/lukasbach"],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukasbach%2Fheadless-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukasbach%2Fheadless-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukasbach%2Fheadless-tree/lists"}