npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@headless-tree/react

v1.5.1

Published

The definitive tree component for the Web

Downloads

207,273

Readme

Headless Tree

Documentation Chat on Discord Follow on Bluesky Follow on X Support on Github Sponsors Follow on Github NPM Core package NPM React package

Super-easy integration of complex tree components into React. Supports ordered and unordered drag-and-drop, extensive keybindings, search, renaming and more. Fully customizable and accessible. Headless Tree is the official successor for react-complex-tree.

It aims to bring the many features of complex tree views, like multi-select, drag-and-drop, keyboard navigation, tree search, renaming and more, while being unopinionated about the styling and rendering of the tree itself. Accessibility is ensured by default, and the integration is extremely simple and flexible.

The interface gives you a flat list of tree nodes that you can easily render yourself, which keeps the complexity of the code low and allows you to customize the tree to your needs. This flat structure also allows you to virtualize the tree with any virtualization library you want. The library automatically provides the necessary aria tags to emulate a nested tree structure, so that accessibility requirements are met despite the flat structure.

Dive into the Get Started page to find out how to use Headless Tree, or have a look at the samples on the Headless Tree Homepage to get an idea of what you can do with it.

[!TIP]
Headless Tree is now available as Beta! The library is mostly stable and production ready, and will be generally released within two months, once I have collected feedback and fixed any bugs that might arise. I've written a blog post about the details of the change, and the future of the library.

Join the Discord to get involved, and follow on Bluesky to stay up to date.

Features

  • Simple Interface: Easy integration in React with full customizability of DOM
  • Drag and Drop: Powerful ordered drag-and-drop, that can interact with external drag events
  • Scalable: Headless Tree remains performant even with large trees
  • Virtualization Support: Compatible with common virtualization library to support 100k+ items
  • Hotkeys!: Lots of hotkeys, fully customizable
  • Search Support: Typeahead anywhere in the tree to quickly search the entire tree
  • Rename items: Optionally allow users to rename items inside the tree
  • Manage State: Let Headless Tree manage tree state internally, or manage any part of it yourself
  • Customize Behavior: Easily overwrite internal behavior like requiring double clicks on items to expand
  • Customize Logic: Overwrite or expand any internal behavior of Headless Tree
  • Async Data Support: Use synchronous or asynchronous data sources for your tree. Headless Tree comes with optional caching for async data
  • Free of dependencies
  • Or check out this comprehensive playground that has most of the capabilities enabled.

Bundle Size

Headless Tree exports individual features in a tree-shaking-friendly way, allowing you to only include what you need to keep your bundle size small. Listed bundle sizes are based on min+gzipped bundles, and are based on the Bundlephobia report as of Headless Tree v0.0.15.

| Feature | Bundle Size | |------------------------|-------------| | Tree Core | 3.1kB | | Sync Data Loader | 0.8kB | | Async Data Loader | 1.4kB | | Selections | 1.1kB | | Drag and Drop | 2.8kB | | Keyboard Drag and Drop | 2.7kB | | Hotkeys | 0.8kB | | Tree Search | 1.3kB | | Renaming | 0.9kB | | Expand All | 0.7kB | | React Bindings | 0.4kB |

Total bundle size is 9.5kB plus 0.4kB for the React bindings. Note that the sum of features is bigger than the total bundle size, because several features share code. Tree-shaking will ensure that the minimum amount of code is included in your bundle.

Get Started

[!TIP]
You can find a comprehensive get-started guide on the documentation homepage. The following gives a brief overview.

Install Headless Tree via npm:

npm install @headless-tree/core @headless-tree/react

In your react component, call the useTree hook from @headless-tree/react with the configuration of your tree:

import {
  hotkeysCoreFeature,
  selectionFeature,
  syncDataLoaderFeature,
} from "@headless-tree/core";
import { useTree } from "@headless-tree/react";

const tree = useTree<string>({
  initialState: { expandedItems: ["folder-1"] },
  rootItemId: "folder",
  getItemName: (item) => item.getItemData(),
  isItemFolder: (item) => !item.getItemData().endsWith("item"),
  dataLoader: {
    getItem: (itemId) => itemId,
    getChildren: (itemId) => [
      `${itemId}-folder`,
      `${itemId}-1-item`,
      `${itemId}-2-item`,
    ],
  },
  indent: 20,
  features: [syncDataLoaderFeature, selectionFeature, hotkeysCoreFeature],
});

Then, render your tree based on the tree instance returned from the hook:

<div {...tree.getContainerProps()} className="tree">
  {tree.getItems().map((item) => (
    <button
      {...item.getProps()}
      key={item.getId()}
      style={{ paddingLeft: `${item.getItemMeta().level * 20}px` }}
    >
      <div
        className={cn("treeitem", {
          focused: item.isFocused(),
          expanded: item.isExpanded(),
          selected: item.isSelected(),
          folder: item.isFolder(),
        })}
      >
        {item.getItemName()}
      </div>
    </button>
  ))}
</div>

Read on in the get started guide to learn more about how to use Headless Tree, and how to customize it to your needs.