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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@live-codes/file-tree

v0.1.0

Published

A zero-dependency, framework-agnostic file tree component with drag-and-drop, context menus, theming, and RTL support.

Downloads

44

Readme

@live-codes/file-tree

A zero-dependency, framework-agnostic file tree component written in TypeScript. Features drag-and-drop, context menus, keyboard navigation, theming, and RTL support.

For use in LiveCodes.

Install

npm install @live-codes/file-tree

Quick Start

import { FileTree } from "@live-codes/file-tree";
import "@live-codes/file-tree/styles.css";

const tree = new FileTree("#container", {
  data: [
    { path: "src/index.ts", type: "file" },
    { path: "src/utils/helpers.ts", type: "file" },
    { path: "src/utils/constants.ts", type: "file" },
    { path: "package.json", type: "file" },
    { path: "README.md", type: "file" },
  ],
  selected: "src/index.ts",
  theme: "dark",
  direction: "ltr",
});

// Listen to events
tree.on("select", (e) => console.log("Selected:", e.path));
tree.on("rename", (e) => console.log("Renamed:", e.oldPath, "->", e.path));
tree.on("move", (e) => console.log("Moved:", e.oldPath, "->", e.path));
tree.on("delete", (e) => {
  e.preventDefault();
  const confirmed = confirm(`Delete "${e.path}"?`);
  if (confirmed) tree.removeNode(e.path);
});
tree.on("change", (e) => console.log("Tree changed:", e.tree));

Parent folders are automatically created from paths. In the example above, the src and src/utils folders are inferred from the file paths — you don't need to declare them.

You can also declare folders explicitly when you want empty folders or want to attach metadata:

const tree = new FileTree("#container", {
  data: [
    { path: "src", type: "folder" },
    { path: "src/index.ts", type: "file" },
    { path: "dist", type: "folder" }, // empty folder
  ],
});

Constructor

new FileTree(container: HTMLElement | string, options?: FileTreeOptions)

The container argument can be a CSS selector string or an HTMLElement.

Node Data

interface FileTreeNodeData {
  /** Full path (e.g. "src/utils/helpers.ts") — used as the unique identifier. */
  path: string;
  /** Whether this is a file or folder. */
  type: "file" | "folder";
  /** Custom SVG string to override the default icon. */
  icon?: string;
  /** Arbitrary user data. */
  meta?: Record<string, unknown>;
}

createNode Helper

The createNode utility returns an array that includes the requested node plus all intermediate parent folders:

import { createNode } from "@live-codes/file-tree";

const nodes = createNode("src/components/Button.tsx", "file");
// Returns:
// [
//   { path: 'src', type: 'folder' },
//   { path: 'src/components', type: 'folder' },
//   { path: 'src/components/Button.tsx', type: 'file' },
// ]

Spread multiple createNode calls into your data array — duplicates are automatically deduplicated:

const tree = new FileTree("#container", {
  data: [
    ...createNode("src/index.ts", "file"),
    ...createNode("src/utils.ts", "file"),
    ...createNode("package.json", "file"),
  ],
});

Options

| Option | Type | Default | Description | | ------------- | ----------------------------- | --------- | ---------------------------------------- | | data | FileTreeNodeData[] | [] | Initial flat data array | | selected | string | '' | Path of the initially selected node | | theme | 'light' \| 'dark' | 'dark' | Color theme | | direction | 'ltr' \| 'rtl' | 'ltr' | Text direction | | indent | number | 16 | Pixels per indentation level | | dragAndDrop | boolean | true | Enable drag and drop | | toolbar | ToolbarOptions \| false | See below | Toolbar configuration | | contextMenu | ContextMenuOptions \| false | See below | Context menu configuration | | icons | Record<string, string> | {} | Custom file extension → SVG icon map | | sort | boolean \| Comparator | true | Sort nodes (folders first, alphabetical) |

ToolbarOptions

{
  createFile?: boolean;    // default: true
  createFolder?: boolean;  // default: true
  expandAll?: boolean;     // default: true
  collapseAll?: boolean;   // default: true
  custom?: ToolbarButton[];
}

ContextMenuOptions

{
  createFile?: boolean;    // default: true
  createFolder?: boolean;  // default: true
  rename?: boolean;        // default: true
  delete?: boolean;        // default: true
  copy?: boolean;          // default: false
  custom?: ContextMenuItem[];
}

Custom Toolbar Button

interface ToolbarButton {
  id: string;
  label: string;
  icon?: string; // SVG string
  title?: string; // Tooltip
  onClick: () => void;
}

Custom Context Menu Item

interface ContextMenuItem {
  id: string;
  label: string;
  icon?: string;
  shortcut?: string;
  visible?: (node: FileTreeNodeData) => boolean;
  onClick: (node: FileTreeNodeData) => void;
}

Methods

Tree Navigation

| Method | Description | | ---------------- | -------------------- | | expand(path) | Expand a folder | | collapse(path) | Collapse a folder | | expandAll() | Expand all folders | | collapseAll() | Collapse all folders | | select(path) | Select a node |

Data Operations

| Method | Description | | ---------------------------------------- | ------------------------------------------------------------ | | addNode(node) | Add a node (parent folders auto-created from path) | | removeNode(path) | Remove a node and its descendants | | renameNode(path, newName) | Rename a node (changes only the last path segment) | | moveNode(sourcePath, targetParentPath) | Move a node to a new parent folder ('' or null for root) | | setData(data) | Replace the entire tree | | getData() | Get a clone of the flat data array | | getNode(path) | Get a single node by path | | getSelectedNode() | Get the currently selected node |

Theme & Direction

| Method | Description | | ------------------------------ | --------------------- | | setTheme('light' \| 'dark') | Change the theme | | getTheme() | Get current theme | | setDirection('ltr' \| 'rtl') | Change text direction | | getDirection() | Get current direction |

Lifecycle

| Method | Description | | ----------- | ------------------------------------------ | | destroy() | Remove the tree and clean up all listeners |

Events

tree.on(eventType, handler);
tree.off(eventType, handler);

| Event | Fired when | | ---------- | ----------------------------------------------- | | select | A node is selected | | expand | A folder is expanded | | collapse | A folder is collapsed | | create | A new node is created (after name is committed) | | rename | A node is renamed | | delete | A node is deleted | | move | A node is moved via drag-and-drop or API | | drop | External files are dropped into the tree | | change | Any structural change to the tree data |

Every event handler receives a FileTreeEvent:

interface FileTreeEvent {
  type: FileTreeEventType;
  node: FileTreeNodeData; // The affected node
  path: string; // Current path (same as node.path)
  oldPath?: string; // Previous path (rename/move)
  parentPath: string; // Parent folder path ('' for root)
  parentNode: FileTreeNodeData | null;
  tree: FileTreeNodeData[]; // Full flat data snapshot
  data?: { files: FileList; items: DataTransferItemList }; // Drag-and-drop
}

Keyboard Shortcuts

| Key | Action | | ----------------- | ------------------------------------ | | / | Navigate between visible nodes | | | Expand folder or move to first child | | | Collapse folder or move to parent | | Enter / Space | Toggle folder expand/collapse | | F2 | Rename selected node | | Delete | Delete selected node |

CSS Customization

All visual properties are controlled by CSS custom properties. Override them on .ft-root or on theme-specific selectors:

.ft-root[data-theme="dark"] {
  --ft-bg: #1a1b26;
  --ft-color: #c0caf5;
  --ft-node-hover: #292e42;
  --ft-node-selected: #33467c;
  --ft-drop-indicator: #7aa2f7;
  /* ... see styles.css for all variables */
}

Integration with Custom Apps

Map the file tree variables to your app's existing CSS variables:

.ft-root[data-theme="dark"] {
  --ft-bg: var(--layout);
  --ft-color: var(--link);
  --ft-node-hover: var(--darker-bg-active);
  --ft-node-selected: var(--dark-bg-active);
  --ft-toolbar-bg: var(--layout);
  --ft-toolbar-border: var(--color30);
  --ft-context-bg: var(--dropdown-bg-color);
  --ft-context-border: var(--dark-bg-color);
  --ft-context-color: var(--dropdown-color);
  --ft-context-hover: var(--dropdown-bg-active);
  --ft-input-bg: var(--input-bg-color);
  --ft-input-color: var(--input-color);
  --ft-input-border: var(--input-border-color);
  --ft-border-radius: var(--rs);
}

.ft-root[data-theme="light"] {
  --ft-bg: var(--layout);
  --ft-color: var(--dark-color);
  --ft-node-hover: var(--dark-bg-active);
  --ft-node-selected: var(--color80);
  --ft-toolbar-bg: var(--layout);
  --ft-toolbar-border: var(--color80);
  --ft-context-bg: var(--dropdown);
  --ft-context-color: var(--dark-color);
}

Utility Exports

The library exports a few utility functions for working with paths:

import {
  createNode, // Create node(s) with auto parent folders
  normalizePath, // Normalize a path string
  getName, // "src/index.ts" → "index.ts"
  getParentPath, // "src/index.ts" → "src"
  getExtension, // "index.ts" → "ts"
} from "@live-codes/file-tree";

Browser Support

All modern browsers (Chrome, Firefox, Safari, Edge). Uses standard HTML5 Drag and Drop API and CSS custom properties.

License

MIT