@pierre/trees is an open source file tree rendering library. It's built for performance and flexibility, is super customizable, and comes packed with features. Made by The Pierre Computer Company.
Currently v1.0.0-beta.6
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051import type { ButtonHTMLAttributes, ReactNode } from 'react';
import { cn } from '../utils/cn';
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; size?: 'sm' | 'md' | 'lg'; isLoading?: boolean; children: ReactNode;}
const VARIANT_CLASSES: Record<NonNullable<ButtonProps['variant']>, string> = { primary: 'bg-brand-600 text-white hover:bg-brand-500', secondary: 'bg-zinc-200 text-zinc-900 hover:bg-zinc-300', ghost: 'bg-transparent text-zinc-200 hover:bg-white/10', danger: 'bg-danger text-white hover:brightness-110',};
const SIZE_CLASSES: Record<NonNullable<ButtonProps['size']>, string> = { sm: 'px-2 py-1 text-xs', md: 'px-3 py-1.5 text-sm', lg: 'px-4 py-2 text-base',};
export function Button({ variant = 'primary', size = 'md', isLoading = false, className, disabled, children, ...rest}: ButtonProps) { return ( <button {...rest} disabled={disabled ?? isLoading} aria-busy={isLoading || undefined} className={cn( 'inline-flex items-center justify-center rounded font-medium transition', 'disabled:cursor-not-allowed disabled:opacity-60', VARIANT_CLASSES[variant], SIZE_CLASSES[size], className, )} > {children} </button> );}
Enable the flattenEmptyDirectories boolean option in the tree options. It collapses single-child folder chains into one row. The result is a more compact tree. Tree-shape options…
Use the gitStatus option to show status badges for added, modified, deleted, renamed, untracked, and ignored files. Ignored items inherit their styling and show no indicator. Folders with changed descendants get a dot indicator automatically.
| Indicator | State | Description |
|---|---|---|
| M | modified | Tracked file with uncommitted changes |
| A | added | New file staged in the working tree |
| D | deleted | Tracked file removed from the working tree |
| R | renamed | Tracked file moved or renamed |
| U | untracked | New file not yet tracked by Git |
None | ignored | Path excluded by gitignore; inherits muted styling |
| ● | descendant | Folder contains changed descendants |
Render your own custom context menu with composition.contextMenu and the React renderContextMenu prop. This demo shows trigger modes for right-click, the trigger button, or both. It also shows menu actions for new files, new folders, rename, and delete. This demo uses Shadcn UI components for the context menu as an example. Your app can use the menus that you already have.
Set dragAndDrop: true to move files and folders. Drag them onto other folders, flattened folders, or the root. Drop targets open automatically when you hover. The tree disables dragging while search is active. Pass a canDrag callback to lock specific paths. Learn more in the item actions guide.
Type in the search field to filter the tree. Search across file paths and names. Trees includes three fileTreeSearchMode options that control how the tree shows non-matching items. The three demos below start with search filled in. They show the different modes.
Built-in, automatic virtualization renders trees with tens of thousands of items instantly. The tree mounts only the visible rows. The tree below contains 2,956 files with every folder expanded. This demo enables stickyFolders.
Trees is accessible to all users by default. It includes built-in keyboard navigation and focus management. It provides the ARIA roles tree and treeitem. It also sets the aria-level, aria-posinset, and aria-setsize attributes. We designed Trees to follow WCAG 2.1 guidance.
| Key | Action |
|---|---|
| ↑↓ | Move focus between items |
| → | Expand folder or move to first child |
| ← | Collapse folder or move to parent |
| EnterSpace | Select focused item; toggle folder |
| CmdSpace | Add or remove focused item from selection |
| a–z | Type-ahead to jump by name |
| Tab | Focus in/out of tree, between search and tree |
Choose the shipped minimal, standard, or complete icon tier. Each tier is cumulative. Override the built-in palette with CSS variables like --trees-file-icon-color-javascript. Or use a fully custom sprite. See the FileTreeIconConfig reference for the full API.
Want matching file icons in your editor? Install Pierre Icons for VS Code to bring the same icon set into your sidebar.
The same Shiki themes from @pierre/diffs can style the FileTree. The theme you choose sets the sidebar and Git decoration colors. Pick a theme. Switch between light and dark. The tree updates live. See the styling and theming reference for more.
Love the Pierre themes? Install our Pierre Theme pack with light and dark flavors, or learn how to build your own Shiki themes.
Modify the CSS custom properties through the style prop. This overrides the UI and theme colors. Below are three examples: custom light, dark, and Synthwave '84. Each example overrides our default values and the CSS that styles the tree. See the styling and theming reference for more info.
We’re using OKLCH colors here—a modern color space that allows for more uniform colors and more consistent palettes.
Pass density="compact", "default", or "relaxed" (or a custom numeric factor) to useFileTree to tune the tree proportions in one place. The keyword sets both the row height and the spacing factor. See the styling and theming reference for more info.
Collectively, our team brings over 150 years of expertise designing, building, and scaling the world's largest distributed systems at Cloudflare, Coinbase, Discord, GitHub, Reddit, Stripe, X, and others.