Zero runtime dependencies · ESM + CJS · MIT

@grida/tree-view

Headless, agnostic tree-view controller for editors and IDEs. No DOM imports in the core, no widget library on top — just a state machine plus a small set of pure helpers, and you render the rows with whatever framework and stylesheet you want.

One controller, many trees

Same wiring. Wildly different trees.

Each panel below is identical TreeController wiring — different fixture, row renderer, indent geometry, constraint stack. Drag rows, expand chevrons, click to select — it all works.

Grida

Monochrome zinc accent. Eye + lock per row, full reorder drag.

Home
Hero section
Design without limits
Subheading
Get started →
hero-illustration.svg
Features
Card / Canvas
Card / Forms
Card / Database
Footer
Pricing
Assets
logo.svg
wordmark.svg

Figma

Dark layers panel. Components in purple, hidden layers dim, full reorder drag.

LayersPage 1
iPhone 15 — 393×852
iPhone Frame
Status Bar
Content
Card 1
Cover.png
Daily Mix
Card 2
Tab Bar (locked)
Button / Primary
Background
Label
Button / Primary
Star

VS Code

Filesystem semantics — drop is always into the nearest folder. Target highlights in blue. No reordering.

Explorer
src
components
Button.tsx
Card.tsx
app
page.tsx
layout.tsx
globals.css
lib
utils.ts
api.ts
index.ts
public
favicon.ico
vercel.svg
package.json
tsconfig.json
README.md

Finder

Multi-column grid, zebra rows, double-click to expand. Same FS drag rule as VS Code.

softmarshmallow
Name
Documents
grida
README.md
Notes.md
Resume.pdf
Screenshot.png
Downloads
Installer.dmg
Trailer.mp4
Applications
Figma.app
Visual Studio Code.app
Grida.app

Built for editor scale.

The state machine, the math, the intents — packaged so adopters ship a tree in a day, not a quarter.

Zero runtime dependencies

~500 LOC of business logic, ESM + CJS, full TypeScript types. Nothing else gets pulled in.

You own your data

TreeSource is read-only — wrap your editor state; the package never mutates your store.

Headless drag & drop

Pure state machine plus geometry helpers. Compose move constraints, fire move / copy intents, plug into any pointer or touch backend.

Six subscription channels

rows · expanded · focus · drag · selection · intent — fine-grained so a row only re-renders for its own slice.

Keyboard, with type-ahead

Configurable keymap dispatch, default keymap shipped (never auto-wired), platform-consistent modifier composition.

Virtualization-ready

controller.getRows() is a stable flat list — plug straight into @tanstack/react-virtual or any windowing library.

Production-grown

Driven by the same controller as the Grida editor's layers panel. The demo gallery reproduces Figma, VS Code, and Finder from one core.

Optional React peer

Core runs unchanged in Node, Bun, Deno, browser, web worker. React bindings are an opt-in /react subpath.

See every pattern.

The documentation page walks through 18 panels — themed showcases, virtualization at 10,000 rows, inline rename, type-ahead, grouping highlights, and more.