Trees

Overview

File tree is in early active development—APIs are subject to change.

File tree is a library for rendering file trees on the web. It includes vanilla JavaScript and React components, with support for SSR. You get flexible components for building trees with filtering, directory flattening, icons, and customizable styling.

We have an opinionated stance in our architecture: file trees benefit from headless state management. We lean into this by building on top of @headless-tree/core for expansion, selection, keyboard navigation, and search while keeping rendering ergonomic in React and vanilla JavaScript. The UI renders in Shadow DOM for style isolation.

Generally speaking, you'll want to use the FileTree component—it provides an easy-to-use API whether you're in vanilla JavaScript or React. For this overview, we'll show both; the React and vanilla APIs are equivalent.

Rendering Trees

The FileTree component is available in both vanilla JavaScript and React. You pass a list of file paths (and optional options); the tree builds the hierarchy and handles expand/collapse, selection, and search. Examples for both environments are below.

Installation

File tree is published as an npm package. Install it with the package manager of your choice:

Package Exports

The package provides several entry points for different use cases:

PackageDescription
@pierre/treesVanilla JS API and utility functions for building file trees
@pierre/trees/reactReact component for rendering file trees with full interactivity
@pierre/trees/ssrServer-side rendering utilities for pre-rendering the tree with fast first paint
@pierre/trees/web-componentsRegisters the <file-tree-container> custom element and shadow DOM helpers

Core Types

Before diving into the options and components, it's helpful to understand the core data structures used throughout the library.

FileTreeOptions

FileTreeOptions is the main options object for FileTree. Use it when creating a vanilla FileTree instance or when rendering the React <FileTree options={...} /> component. It defines the file list, instance id, flattening behavior, search mode, and other structural behavior.

Tip: To pre-render the tree on the server, use preloadFileTree from @pierre/trees/ssr and pass payload.html as the prerenderedHTML prop (React) or hydrate the same container in vanilla. See SSR for usage.

The initialFiles option

The tree is built from an array of file paths (strings). Folders are inferred from path segments; use forward slashes. Top-level paths (e.g. README.md) and nested paths (e.g. src/components/Button.tsx) are both valid.

That produces a tree with README.md and package.json at the root and a src folder containing index.ts, utils/helpers.ts, and a components folder with Button.tsx.

Options reference

initialFiles is the only required option, all others are optional.

OptionDescription
initialFilesRequired. Array of file paths (strings). Defines the list and hierarchy.
idUnique identifier for this instance (DOM ids, SSR). Default: e.g. ft_brw_1.
flattenEmptyDirectoriesWhen true, single-child folder chains become one row (e.g. build / assets / imagesbuild · assets · images). Default: false. Live demo.
fileTreeSearchModeSearch behavior: 'expand-matches' (default), 'collapse-non-matches', or 'hide-non-matches'.
useLazyDataLoaderWhen true, children load when a folder is expanded. Default: false.
dragAndDropEnables built-in drag and drop interactions. Default: false.
lockedPathsOptional list of file/folder paths that cannot be dragged when drag and drop is enabled.
onCollisionOptional callback for drag collisions. Return true to overwrite destination.
gitStatusOptional GitStatusEntry[] used to show Git-style file status (added, modified, deleted). Folders with changed descendants also receive a change indicator. Live demo.

onSelection is configured in React as a top-level prop (\<FileTree onSelection={...} />) and in vanilla via FileTreeStateConfig (second constructor argument).

onSelection examples

FileTreeSelectionItem

FileTreeSelectionItem describes one item in the tree selection. Your onSelection callback receives an array of these (in vanilla state config or React top-level props). Each item has a path (the file or folder path) and isFolder (whether it's a folder or file).

GitStatus & GitStatusEntry

GitStatusEntry pairs a file path with a status value ('added' | 'modified' | 'deleted'): { path: string; status: 'added' | 'modified' | 'deleted' }.

Import GitStatusEntry from @pierre/trees and use it with gitStatus in FileTree options/props to show Git-style status indicators on files. path should match your tree file paths (for example, src/index.ts).

FileTreeSearchMode

FileTreeSearchMode controls how search affects the tree. Pass it via fileTreeSearchMode in FileTreeOptions.

  • 'expand-matches' (default): expand nodes that match the search.
  • 'collapse-non-matches': hide non-matching branches so only matching paths and their parents stay visible.
  • 'hide-non-matches': keep branch structure but hide non-matching rows.

FileTreeStateConfig

FileTreeStateConfig is the state/callback config for the vanilla FileTree constructor's second argument. Use it for defaults (initialExpandedItems, initialSelectedItems, initialSearchQuery) and callbacks/controlled values (onSelection, onExpandedItemsChange, onSelectedItemsChange, onFilesChange, plus expandedItems/selectedItems/files when controlled).

React API

Import the React component from @pierre/trees/react.

The React API exposes one main component: FileTree, which renders a file tree from a list of file paths with support for selection, search, and customization via options.

Component

Props

FileTree accepts an options object (see FileTree options for full details) plus optional styling and SSR props. initialFiles/state callbacks are top-level props on the React component:

With gitStatus

Use the optional gitStatus prop to pass a controlled array of GitStatusEntry items. Updating gitStatus updates file status indicators (added, modified, deleted) and folder change hints for descendants. Try the live demo at /trees#path-colors.

Vanilla JS API

Import the vanilla JavaScript class from @pierre/trees.

The Vanilla JS API exposes the FileTree class. Create an instance with options, then call render({ fileTreeContainer }) or render({ containerWrapper }) to mount the tree into the DOM (pass a host element to reuse, or a parent to append the host to).

Basic usage

Constructor options and instance methods

FileTree is constructed with an options object (see FileTree options for full details) and an optional FileTreeStateConfig. After construction you can render, update state imperatively, or clean up:

Imperative state methods

Beyond render and cleanUp, FileTree exposes methods to read and update tree state programmatically:

MethodDescription
setFiles(files)Replace the file list and re-render
getFiles()Return the current file list
setExpandedItems(items)Set which folders are expanded
getExpandedItems()Return the currently expanded folder paths
expandItem(path)Expand a single folder
collapseItem(path)Collapse a single folder
toggleItemExpanded(path)Toggle a folder's expanded state
setSelectedItems(items)Set the selected items
getSelectedItems()Return the currently selected item paths
setCallbacks(callbacks)Update callbacks (onSelection, etc.) after construction
setOptions(options, stateConfig?)Merge new options (and optionally state config)

With gitStatus

For VCS integrations, pass gitStatus in constructor options and update it imperatively as changes arrive:

  • fileTree.setGitStatus(entries | undefined) updates the current git statuses and re-renders.
  • fileTree.getGitStatus() returns the current GitStatusEntry[] | undefined.

Try the live behavior at /trees#path-colors.

Utilities

Import utility functions from @pierre/trees. These can be used with any framework or rendering approach.

sortChildren

Sort an array of child paths for display in a file tree. Use this when building custom loaders or when you need a specific sort order. The package exports defaultChildrenComparator (folders first, then dot-prefixed, then case-insensitive alphabetical) and alphabeticalChildrenComparator (simple alphabetical). You can pass a custom comparator to implement your own order.

generateSyncDataLoader

Build a tree data loader from a flat list of file paths. All nodes are computed upfront. FileTree uses this internally when you pass initialFiles (and flattenEmptyDirectories). Use it directly when building custom integrations with the headless tree or when you need the same tree shape elsewhere.

generateLazyDataLoader

Build a tree data loader that computes nodes on demand when folders are expanded. FileTree uses this internally when you pass initialFiles and useLazyDataLoader: true. Best for large trees where most folders stay collapsed.

Styling

The file tree is rendered inside a shadow DOM host (the file-tree-container custom element), so its styles are isolated from your page.

Customize it by passing class and style on the host: use className and style on the React FileTree component, or set them on the host element after render() in vanilla JS. That lets you control layout (e.g. maxHeight, width) and override the tree’s CSS variables (e.g. --ft-font-size, --ft-row-height) in global CSS, on a wrapper, or via the style prop.

For the full list of CSS variables, review style.css in the @pierre/trees package.

Git status styling hooks

When gitStatus is provided, tree rows include status-aware attributes you can target:

  • data-item-git-status="added" | "modified" | "deleted" on changed files
  • data-item-contains-git-change="true" on folders that contain changed files

You can also override these CSS variables:

  • --ft-git-added-color
  • --ft-git-modified-color
  • --ft-git-deleted-color

SSR

Import SSR utilities from @pierre/trees/ssr.

The SSR API lets you pre-render the file tree HTML on the server for fast first paint, then hydrate on the client for full interactivity.

Usage

preloadFileTree returns a payload object: { id, shadowHtml, html }. Pass payload.html to the client as prerenderedHTML (React) and pass the same FileTreeOptions you used on the server. For vanilla hydration, render the pre-rendered container into the page and call hydrate({ fileTreeContainer }).

Options used for pre-rendering must exactly match what you pass on the client. Use the same FileTreeOptions object (or equivalent) when calling preloadFileTree and when rendering FileTree so the tree structure and state hydrate correctly.

Preloaders

preloadFileTree

Preloads the file tree HTML from a FileTreeOptions object and an optional FileTreeStateConfig (for initial expanded/selected items). Use this in a server component or server route; pass the returned payload and the same options to your client component. Pass payload.html to the React FileTree via the prerenderedHTML prop, or use vanilla FileTree and call hydrate() with the server-rendered container.

Vanilla hydration

When using the vanilla FileTree class with SSR, call hydrate() instead of render() and pass the server-rendered container: