Headless Tree Documentation

repository·main·Indexed 21 days ago

https://github.com/lukasbach/headless-tree

A highly customizable, headless library for building complex tree components in React. It provides logic for drag-and-drop, keyboard navigation, search, and multi-selection while leaving UI and styling to the developer. It features a flat list interface for compatibility with virtualization libraries (supporting 100k+ items) and provides automatic ARIA tags for accessibility. The library is the official successor to react-complex-tree and supports both synchronous and asynchronous data loading.

Tokens
32.8K
Snippets
78
Records
158
Agent score
72%

What's inside Headless Tree

  1. What is Headless Tree?

    main

    Headless Tree is a library for integrating complex tree components into React applications. It provides the logic for advanced tree features while remaining unopinionated about styling and rendering.

    Key characteristics:

    • Flat List Interface: Instead of a nested structure, the library provides a flat list of tree nodes. This makes it easy to render and compatible with virtualization libraries (like react-window or react-virtuoso) to support very large trees (100k+ items).
    • Accessibility: Even though the data structure is flat, the library automatically provides the necessary ARIA tags to emulate a nested tree structure for screen readers.
    • Headless: You are responsible for the DOM and CSS; the library provides the state, keyboard interactions, and accessibility attributes.
    • Successor to react-complex-tree: It is the official successor to the react-complex-tree project.
  2. Drag and Drop capabilities in Headless Tree

    main

    The Drag and Drop feature enables moving tree items within the tree structure and facilitates interactions with external objects.

    Key capabilities include:

    • Internal Reordering: Drag a single tree item or multiple selected items (if the selection feature is enabled) to a new location within the tree.
    • External Dragging: Drag tree items out of the tree to interact with external systems.
    • External Dropping: Drag foreign data objects from outside the tree into the tree.
    • Multi-tree Interaction: Implement drag-and-drop behavior between multiple independent trees.

    For detailed implementation details and setup, refer to the Drag and Drop Overview Page.

  3. How selection works in Headless Tree

    main

    The selection feature enables multiselect capabilities, allowing users to select multiple items simultaneously. Without this feature enabled, Headless Tree only supports focusing a single item.

    Selection is particularly powerful when combined with the drag-and-drop feature, enabling users to select a group of items and move them all at once.

    By default, Headless Tree manages the selected items in its own internal state. However, if you provide a setState or setSelectedItems function in your tree configuration, you can take control of the selection state manually (see Managing State).

  4. How the Main Feature works in Headless Tree

    main
    The main feature provides the core functionality required for most other features in Headless Tree to operate. It is included automatically in the library and does not require an explicit import by the user. This ensures that the fundamental tree logic is always available as a foundation for specialized features (like the tree feature).
  5. Handle loading states for items and children

    main

    The Async Data Loader tracks loading states for items and their children. While getItem or getChildrenWithData is resolving, the item is considered to be in a loading state.

    State Properties

    • state.loadingItems: An array of item IDs currently loading their own data.
    • state.loadingItemChildren: An array of item IDs whose children are currently being fetched.

    Checking Loading Status

    You can check if a specific item is loading by calling item.isLoading().

    Customizing Loading Display

    When an item is loading, its data is set to the value returned by the createLoadingItemData configuration option. This allows you to define placeholder data (e.g., "Loading...") to be used during the fetch.

  6. How features and plugins work in Headless Tree

    main

    Headless Tree uses a plugin-based architecture where individual features (like drag-and-drop or hotkeys) are separate objects. This allows for better tree-shaking and customizability.

    Important Rules:

    • Manual Import Required: You must explicitly import features from @headless-tree/core and add them to the features array in your TreeConfig.
    • Runtime Availability: If you attempt to use a method or config option provided by a feature but haven't included that feature in your features array, the method will not work at runtime (even if TypeScript doesn't complain).
    • Built-in Features: "Tree Core" and "Main Feature" are always included and do not need to be manually added.

    Example of adding features:

    import { dragAndDropFeature, hotkeysCoreFeature, syncDataLoaderFeature } from "@headless-tree/core";
    import { useTree } from "@headless-tree/react";
    
    useTree({
        features: [
            syncDataLoaderFeature,
            dragAndDropFeature,
            hotkeysCoreFeature,
        ]
    });
    import { dragAndDropFeature, hotkeysCoreFeature, syncDataLoaderFeature } from "@headless-tree/core";
    import { useTree } from "@headless-tree/react";
    
    useTree({
        // ... other options
        features: [
            syncDataLoaderFeature,
            dragAndDropFeature,
            hotkeysCoreFeature,
        ]
    })
  7. How the Hotkeys Core feature works

    main

    The Hotkeys Core feature is the foundational engine required for any keyboard-based interaction in the tree. While individual features (like the Selection Feature) define their own specific hotkey configurations (e.g., selectAll defaulting to Ctrl+A), they do not handle the actual keyboard event listening.

    Only the Hotkeys Core feature implements the logic to listen for and handle keyboard events. You must include the Hotkeys Core feature in your tree configuration for any other feature's hotkeys to function.

  8. How features work in Headless Tree

    main

    Headless Tree is built using a modular feature system. Instead of a monolithic core, functionality is provided by individual feature objects that can be optionally included in the tree configuration. This allows for reduced bundle sizes by only including necessary features and enables deep customization.

    Each feature is an object imported from @headless-tree/core that interacts with the tree through several interfaces:

    • State: The feature's substate is merged into the global TreeState. You can manage this state using the provided state setters or your own setState function.
    • Config: Feature-specific configuration options are merged into the global TreeConfig.
    • Tree Instance: Methods provided by the feature that are accessible via the TreeInstance (e.g., tree.someFeatureMethod()).
    • Item Instance: Methods provided by the feature that are accessible via the ItemInstance (e.g., tree.getItemInstance(id).someFeatureMethod()).
    • Hotkeys: If the hotkeysCoreFeature is included, the feature's defined hotkeys will be active and can be customized via the hotkeys config object.
    const tree = useTree<string>({
      // ...remaining tree config
      state: { selectedItems: ["item-1", "item-2"] },
      setSelectedItems: myCustomSetSelectedItems,
    
      hotkeys: {
        // Override hotkey definitions for this feature
        selectAll: {
          hotkey: "ctrl+q",
        },
      },
      features: [
        syncDataLoaderFeature,
        selectionFeature,
        hotkeysCoreFeature,
      ],
    });
    
    // Interact with tree instance methods
    tree.setSelectedItems(["item-3", "item-4"]);
    
    // Interact with item instance methods
    tree.getItemInstance("item-1").select();
  9. Understand Reparenting behavior in Drag and Drop

    main
    In Headless Tree, 'Reparenting' is a specific drag-and-drop behavior used when an item is dragged onto the lower half of the bottom-most item in a tree. Instead of being dropped as a sibling or child of the bottom item, the target folder is determined by the horizontal offset of the dragged item. This allows users to visually indicate which branch or folder they intend to reparent the item into based on where they hover horizontally.
  10. Headless Tree Features

    main

    Headless Tree is highly modular. You can enable specific features to keep your bundle size small. Supported features include:

    • Drag and Drop: Ordered drag-and-drop, including interaction with external drag events.
    • Keyboard Navigation: Extensive and customizable hotkeys.
    • Search: Typeahead support to find items anywhere in the tree.
    • Selection: Multi-select capabilities.
    • Renaming: Ability to allow users to rename items.
    • Data Loading: Supports both synchronous and asynchronous data sources (with optional caching for async).
    • Virtualization: Designed to work with any virtualization library for high performance with large datasets.
    • State Management: Choose between letting Headless Tree manage state internally or managing it yourself.