TreeForge
Modern File Tree Component for the Web
A lightweight, dependency-free JavaScript library for rendering beautiful, interactive file trees. Perfect for sandboxes, editors, and learning platforms.
Why TreeForge?
Everything you need to build amazing file tree interfaces
15 Beautiful Themes
Choose from GitHub, VS Code, Dracula, Nord, and 11 more professionally designed themes.
Explore themes →15 Configuration Presets
Ready-to-use configs for common use cases: file managers, code editors, documentation browsers.
View presets →10 Lifecycle Hooks
Complete control with hooks for file operations, drag & drop, and custom interactions.
Learn more →Zero Dependencies
Pure vanilla JavaScript. No jQuery, no React, no framework required. Just plug and play.
Lightning Fast
Optimized for performance. Handles large trees with thousands of nodes effortlessly.
Responsive Design
Works perfectly on desktop, tablet, and mobile. Touch-friendly with gesture support.
Highly Configurable
100+ configuration options. Customize every aspect to match your design needs.
API Integration
Works with any backend. Support for local data, REST APIs, and real-time updates.
Accessible
WCAG compliant with keyboard navigation, ARIA labels, and screen reader support.
Get Started in Seconds
Install via npm or use directly from CDN
npm install treeforge
yarn add treeforge
<script src="https://cdn.jsdelivr.net/npm/treeforge@1.0.2/index.js"></script>
Quick Start Example
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
const tree = new TreeForge({
containerId: 'tree',
localData: {
name: 'my-project',
type: 'folder',
children: [
{ name: 'src', type: 'folder', children: [] },
{ name: 'README.md', type: 'file' }
]
},
...ConfigPresets.GITHUB_CLONE // Use a preset!
});
Quick Start Guide
Get up and running in 5 minutes
Step 1: Install TreeForge
npm install treeforge
Step 2: Import and Initialize
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
// Create your tree data
const myData = {
name: 'project',
type: 'folder',
children: [
{ name: 'src', type: 'folder', children: [] },
{ name: 'README.md', type: 'file' }
]
};
// Initialize TreeForge
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
...ConfigPresets.GITHUB_CLONE
});
Step 3: Add HTML Container
<div id="tree"></div>
Next Steps
- Explore Configuration Options
- Learn about Data Structure
- Check out Live Examples
- Browse Available Themes
Configuration
Customize every aspect of TreeForge
Basic Configuration
const tree = new TreeForge({
containerId: 'tree', // Required: DOM element ID
localData: treeData, // Local data source
apiUrl: '/api/tree', // Or API endpoint
settings: {
style: 'modern', // Visual style
colors: {...}, // Color scheme
icons: {...} // Custom icons
},
features: {
contextMenu: true, // Right-click menu
dragDrop: true, // Drag and drop
search: true, // Search functionality
keyboard: true, // Keyboard shortcuts
editor: true // File editor
}
});
Settings Object
Control the visual appearance and behavior:
style- Visual style preset (modern, minimal, colorful)colors- Custom color schemeicons- File and folder iconsindent- Indentation sizelineHeight- Line height for nodesfontSize- Font size for text
Features Object
Enable or disable specific features:
contextMenu- Right-click context menudragDrop- Drag and drop nodessearch- Search bar and functionalitykeyboard- Keyboard navigationeditor- Built-in file editortoolbar- Action toolbar
Data Structure
Understanding TreeForge data format
Tree Node Format
{
name: 'filename.js', // Required: Node name
type: 'file', // Required: 'file' or 'folder'
children: [], // Optional: Child nodes (for folders)
path: '/src/app.js', // Optional: Full path
content: 'code...', // Optional: File content
metadata: { // Optional: Custom metadata
size: 1024,
modified: '2025-10-06',
permissions: 'rw-r--r--'
}
}
Complete Example
const projectData = {
name: 'my-project',
type: 'folder',
children: [
{
name: 'src',
type: 'folder',
children: [
{
name: 'index.js',
type: 'file',
content: 'console.log("Hello");'
},
{
name: 'components',
type: 'folder',
children: [
{ name: 'Header.js', type: 'file' },
{ name: 'Footer.js', type: 'file' }
]
}
]
},
{
name: 'package.json',
type: 'file',
content: '{ "name": "my-project" }'
}
]
};
API Response Format
When using an API endpoint, return data in the same format:
// GET /api/tree
{
"success": true,
"data": {
"name": "root",
"type": "folder",
"children": [...]
}
}
Live Examples
See TreeForge in action with different styles and configurations
import TreeForge, { TreeStyles } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: projectData,
settings: TreeStyles.GITHUB,
features: {
contextMenu: true,
dragDrop: true,
search: true
}
});
import TreeForge, { TreeStyles } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: projectData,
settings: TreeStyles.VSCODE_DARK,
features: {
editor: true,
keyboard: true,
autoSave: true
}
});
import TreeForge, { TreeStyles } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: projectData,
settings: TreeStyles.DRACULA,
features: {
contextMenu: true,
dragDrop: true
}
});
import TreeForge, { TreeStyles } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: projectData,
settings: TreeStyles.MINIMAL
});
15 Beautiful Themes
Choose the perfect style for your project
GitHub
Classic GitHub file browser style
TreeStyles.GITHUB
VS Code Dark
VS Code's dark theme
TreeStyles.VSCODE_DARK
VS Code Light
VS Code's light theme
TreeStyles.VSCODE_LIGHT
Dracula
Popular Dracula theme
TreeStyles.DRACULA
Nord
Arctic, north-bluish theme
TreeStyles.NORD
Colorful
Vibrant, colorful design
TreeStyles.COLORFUL
Material Dark
Material Design dark
TreeStyles.MATERIAL_DARK
Material Light
Material Design light
TreeStyles.MATERIAL_LIGHT
ASCII
Classic ASCII art style
TreeStyles.ASCII
Minimal
Clean, minimal design
TreeStyles.MINIMAL
One Dark
Atom One Dark theme
TreeStyles.ONE_DARK
Solarized Dark
Solarized color scheme
TreeStyles.SOLARIZED_DARK
Constructor
Creating a TreeForge instance
Syntax
new TreeForge(config)
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
containerId |
string | ✅ Yes | ID of the DOM element to render the tree |
localData |
object | ❌ No* | Local tree data (required if no apiUrl) |
apiUrl |
string | ❌ No* | API endpoint for tree data (required if no localData) |
settings |
object | ❌ No | Visual settings and styling |
features |
object | ❌ No | Feature flags (contextMenu, dragDrop, etc.) |
hooks |
object | ❌ No | Lifecycle hooks and callbacks |
Example
const tree = new TreeForge({
containerId: 'my-tree',
localData: treeData,
settings: TreeStyles.GITHUB,
features: {
contextMenu: true,
dragDrop: true
},
hooks: {
onCreateFile: (path) => console.log('Created:', path)
}
});
Methods
Control your tree programmatically
render()
Renders or re-renders the tree.
tree.render();
refresh()
Refreshes the tree data (useful for API mode).
await tree.refresh();
destroy()
Destroys the tree instance and cleans up.
tree.destroy();
createNode(path, data)
Creates a new node at the specified path.
tree.createNode('/src', {
name: 'app.js',
type: 'file',
content: 'console.log("Hello");'
});
deleteNode(path)
Deletes a node at the specified path.
tree.deleteNode('/src/app.js');
renameNode(path, newName)
Renames a node at the specified path.
tree.renameNode('/src/app.js', 'index.js');
getNode(path)
Gets node data at the specified path.
const node = tree.getNode('/src/app.js');
console.log(node.name, node.type);
expandAll() / collapseAll()
Expands or collapses all folders.
tree.expandAll();
tree.collapseAll();
Properties
Access tree instance properties
| Property | Type | Read-only | Description |
|---|---|---|---|
tree.data |
object | ❌ No | The current tree data structure |
tree.config |
object | ✅ Yes | The configuration object |
tree.container |
HTMLElement | ✅ Yes | The DOM container element |
tree.selected |
object | ❌ No | Currently selected node |
tree.version |
string | ✅ Yes | TreeForge version number |
Example Usage
// Access tree data
console.log(tree.data);
// Get selected node
if (tree.selected) {
console.log('Selected:', tree.selected.name);
}
// Check version
console.log('TreeForge version:', tree.version);
Events
Listen to tree events
Available Events
| Event | Parameters | Description |
|---|---|---|
node:select |
node, event | Fired when a node is selected |
node:expand |
node | Fired when a folder is expanded |
node:collapse |
node | Fired when a folder is collapsed |
node:create |
path, data | Fired when a node is created |
node:delete |
path | Fired when a node is deleted |
node:rename |
path, oldName, newName | Fired when a node is renamed |
tree:ready |
- | Fired when tree is fully loaded |
Listening to Events
// Listen to node selection
tree.on('node:select', (node, event) => {
console.log('Selected:', node.name);
});
// Listen to node creation
tree.on('node:create', (path, data) => {
console.log('Created:', path);
});
// Listen to tree ready
tree.on('tree:ready', () => {
console.log('Tree is ready!');
});
Removing Event Listeners
// Remove specific listener
const handler = (node) => console.log(node);
tree.on('node:select', handler);
tree.off('node:select', handler);
// Remove all listeners for an event
tree.off('node:select');
Lifecycle Hooks
Hook into TreeForge lifecycle
Available Lifecycle Hooks
onLoad
Called when the tree is initially loaded.
hooks: {
onLoad: (data) => {
console.log('Tree loaded with data:', data);
}
}
onRender
Called after the tree is rendered.
hooks: {
onRender: () => {
console.log('Tree rendered successfully');
}
}
onDestroy
Called when the tree instance is destroyed.
hooks: {
onDestroy: () => {
console.log('Cleaning up resources...');
}
}
Complete Example
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
hooks: {
onLoad: (data) => {
console.log('Loaded nodes:', data.children.length);
},
onRender: () => {
console.log('Tree is visible');
},
onDestroy: () => {
console.log('Goodbye!');
}
}
});
File Operations Hooks
Handle file-related actions
onCreateFile
Called when a file is created.
hooks: {
onCreateFile: (path) => {
console.log('File created:', path);
// Save to backend
fetch('/api/files', {
method: 'POST',
body: JSON.stringify({ path })
});
}
}
onDeleteFile
Called when a file is deleted.
hooks: {
onDeleteFile: (path) => {
if (confirm(`Delete ${path}?`)) {
console.log('File deleted:', path);
return true; // Allow deletion
}
return false; // Cancel deletion
}
}
onReadFile
Called when a file is opened/read.
hooks: {
onReadFile: async (path) => {
const response = await fetch(`/api/files${path}`);
const content = await response.text();
return content;
}
}
onWriteFile
Called when a file is saved.
hooks: {
onWriteFile: async (path, content) => {
await fetch(`/api/files${path}`, {
method: 'PUT',
body: content
});
console.log('File saved:', path);
}
}
onFileOpen
Called when a file is clicked/opened.
hooks: {
onFileOpen: (node) => {
console.log('Opening file:', node.name);
// Open in editor, download, etc.
}
}
Folder Operations Hooks
Handle folder-related actions
onCreateFolder
Called when a folder is created.
hooks: {
onCreateFolder: (path) => {
console.log('Folder created:', path);
fetch('/api/folders', {
method: 'POST',
body: JSON.stringify({ path })
});
}
}
onDeleteFolder
Called when a folder is deleted.
hooks: {
onDeleteFolder: (path, node) => {
const fileCount = node.children?.length || 0;
if (fileCount > 0) {
return confirm(`Delete folder with ${fileCount} items?`);
}
return true;
}
}
onRenameNode
Called when a file or folder is renamed.
hooks: {
onRenameNode: (oldPath, newPath) => {
console.log(`Renamed: ${oldPath} → ${newPath}`);
fetch('/api/rename', {
method: 'PATCH',
body: JSON.stringify({ oldPath, newPath })
});
}
}
onDeleteNode
Called when any node (file/folder) is deleted.
hooks: {
onDeleteNode: (path, type) => {
console.log(`Deleting ${type}:`, path);
// Return false to cancel, true to proceed
return confirm(`Delete this ${type}?`);
}
}
Custom Hooks
Create your own hook patterns
Combining Multiple Hooks
import { combineHooks } from 'treeforge';
const analyticsHooks = {
onCreateFile: (path) => {
analytics.track('file_created', { path });
},
onDeleteFile: (path) => {
analytics.track('file_deleted', { path });
}
};
const apiHooks = {
onCreateFile: (path) => {
return fetch('/api/files', {
method: 'POST',
body: JSON.stringify({ path })
});
}
};
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
hooks: combineHooks(analyticsHooks, apiHooks)
});
Hook Utilities
import {
LocalStorageHooks,
RestApiHooks,
AnalyticsHooks,
ValidationHooks
} from 'treeforge';
// Use built-in hook sets
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
hooks: {
...LocalStorageHooks,
...AnalyticsHooks
}
});
Custom Hook Example
// Create reusable hook sets
const MyCustomHooks = {
onCreateFile: (path) => {
// Custom logic
notifyUser(`Created: ${path}`);
logToServer('create', path);
},
onDeleteFile: (path) => {
// Custom validation
if (isProtected(path)) {
alert('This file is protected!');
return false; // Cancel deletion
}
return true; // Allow deletion
}
};
// Use in multiple trees
const tree1 = new TreeForge({
containerId: 'tree1',
localData: data1,
hooks: MyCustomHooks
});
const tree2 = new TreeForge({
containerId: 'tree2',
localData: data2,
hooks: MyCustomHooks
});
Configuration Presets
Ready-to-use configurations for common use cases
Using Presets
import TreeForge, { ConfigPresets } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
...ConfigPresets.GITHUB_CLONE // Use a preset!
});
Available Presets
GITHUB_CLONE
GitHub file browser style with all features
...ConfigPresets.GITHUB_CLONE
VSCODE_CLONE
VS Code explorer with editor integration
...ConfigPresets.VSCODE_CLONE
FILE_MANAGER
Full-featured file manager
...ConfigPresets.FILE_MANAGER
DOCS_BROWSER
Documentation browser (read-only)
...ConfigPresets.DOCS_BROWSER
MINIMAL
Minimal tree, no extra features
...ConfigPresets.MINIMAL
MOBILE_OPTIMIZED
Touch-friendly mobile interface
...ConfigPresets.MOBILE_OPTIMIZED
Customizing Presets
// Start with a preset, override specific options
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
...ConfigPresets.GITHUB_CLONE,
settings: {
...ConfigPresets.GITHUB_CLONE.settings,
colors: {
background: '#1a1a1a', // Custom background
text: '#ffffff'
}
}
});
Custom Styling
Customize the look and feel
Using CSS Variables
/* Override TreeForge CSS variables */
#tree {
--tf-bg-primary: #1a1a1a;
--tf-bg-secondary: #2d2d2d;
--tf-text-color: #e0e0e0;
--tf-accent-color: #1fb6ff;
--tf-border-color: #444;
--tf-hover-bg: rgba(255, 255, 255, 0.1);
}
Custom CSS Classes
/* Target specific elements */
.tf-node {
padding: 8px 12px;
border-radius: 6px;
}
.tf-node:hover {
background: #2d2d2d;
}
.tf-node[data-type="folder"] {
font-weight: 600;
}
.tf-node[data-type="file"][data-ext=".js"] {
color: #f7df1e; /* Yellow for JS files */
}
JavaScript Styling
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
settings: {
colors: {
background: '#1a1a1a',
text: '#e0e0e0',
accent: '#1fb6ff',
hover: 'rgba(31, 182, 255, 0.08)'
},
icons: {
folder: '📁',
folderOpen: '📂',
file: '📄',
fileJs: '⚡',
fileCss: '🎨',
fileHtml: '🌐'
},
fontSize: '14px',
lineHeight: '1.6',
indent: 20
}
});
Theme Example
// Create a custom theme
const MyDarkTheme = {
style: 'custom',
colors: {
background: '#0d1117',
backgroundHover: '#161b22',
text: '#c9d1d9',
textSecondary: '#8b949e',
accent: '#58a6ff',
border: '#30363d'
},
icons: {
folder: '📁',
file: '📄'
},
fontSize: '14px',
indent: 16
};
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
settings: MyDarkTheme
});
Framework Integration
Use TreeForge with your favorite framework
React Integration
import { useEffect, useRef } from 'react';
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
function TreeComponent({ data }) {
const treeRef = useRef(null);
const containerRef = useRef(null);
useEffect(() => {
if (containerRef.current && !treeRef.current) {
treeRef.current = new TreeForge({
containerId: containerRef.current.id,
localData: data,
...ConfigPresets.GITHUB_CLONE
});
}
return () => {
if (treeRef.current) {
treeRef.current.destroy();
}
};
}, []);
useEffect(() => {
if (treeRef.current) {
treeRef.current.data = data;
treeRef.current.render();
}
}, [data]);
return ;
}
export default TreeComponent;
Vue Integration
import { onMounted, onUnmounted, ref, watch } from 'vue';
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
export default {
props: ['data'],
setup(props) {
const treeInstance = ref(null);
onMounted(() => {
treeInstance.value = new TreeForge({
containerId: 'tree-container',
localData: props.data,
...ConfigPresets.GITHUB_CLONE
});
});
watch(() => props.data, (newData) => {
if (treeInstance.value) {
treeInstance.value.data = newData;
treeInstance.value.render();
}
});
onUnmounted(() => {
if (treeInstance.value) {
treeInstance.value.destroy();
}
});
return {};
},
template: ``
};
Angular Integration
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
@Component({
selector: 'app-tree',
template: ``
})
export class TreeComponent implements OnInit, OnDestroy {
@Input() data: any;
private tree: any;
ngOnInit() {
this.tree = new TreeForge({
containerId: 'tree-container',
localData: this.data,
...ConfigPresets.GITHUB_CLONE
});
}
ngOnChanges() {
if (this.tree) {
this.tree.data = this.data;
this.tree.render();
}
}
ngOnDestroy() {
if (this.tree) {
this.tree.destroy();
}
}
}
Svelte Integration
<script>
import { onMount, onDestroy } from 'svelte';
import TreeForge, { ConfigPresets } from 'treeforge';
import 'treeforge/styles/ui.css';
export let data;
let tree;
onMount(() => {
tree = new TreeForge({
containerId: 'tree-container',
localData: data,
...ConfigPresets.GITHUB_CLONE
});
});
$: if (tree && data) {
tree.data = data;
tree.render();
}
onDestroy(() => {
if (tree) tree.destroy();
});
</script>
<div id="tree-container"></div>
Performance
Optimize TreeForge for large datasets
Virtual Scrolling
For trees with thousands of nodes, enable virtual scrolling:
const tree = new TreeForge({
containerId: 'tree',
localData: largeData,
features: {
virtualScroll: true, // Enable virtual scrolling
virtualScrollHeight: 400, // Visible height
virtualScrollBuffer: 10 // Buffer rows
}
});
Lazy Loading
Load child nodes on demand:
const tree = new TreeForge({
containerId: 'tree',
localData: initialData,
features: {
lazyLoad: true
},
hooks: {
onExpand: async (node) => {
if (!node.children) {
// Load children from API
const response = await fetch(`/api/tree/${node.path}`);
node.children = await response.json();
}
}
}
});
Debouncing
Debounce frequent operations:
import { debounce } from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
hooks: {
onSearch: debounce((query) => {
// Search logic (debounced)
performSearch(query);
}, 300)
}
});
Performance Tips
- ✅ Use virtual scrolling for 1000+ nodes
- ✅ Enable lazy loading for deep trees
- ✅ Debounce search and filter operations
- ✅ Minimize re-renders by batching updates
- ✅ Use
tree.refresh()instead of recreating - ✅ Disable unnecessary features
Benchmarks
| Nodes | Initial Render | Re-render | Memory |
|---|---|---|---|
| 100 | ~5ms | ~2ms | ~500KB |
| 1,000 | ~40ms | ~15ms | ~2MB |
| 10,000 | ~200ms* | ~80ms* | ~15MB |
* With virtual scrolling enabled
Changelog
What's new in TreeForge
v1.0.0 October 6, 2025
- 🎉 Initial release
- ✨ 15 built-in themes
- ⚙️ 15 configuration presets
- 🪝 10 lifecycle hooks
- 🎨 Complete CSS customization
- 📱 Mobile responsive
- ⚡ Virtual scrolling support
- 🔍 Search and filter
- ✏️ Inline editing
- 🖱️ Drag and drop
- 📝 Context menus
- ⌨️ Keyboard navigation
v0.9.0-beta September 2025
- Beta release for testing
- Core features implemented
- API stabilized
Migration Guide
Upgrading from other libraries
From jstree
// jstree (OLD)
$('#tree').jstree({
'core': {
'data': myData
}
});
// TreeForge (NEW)
import TreeForge from 'treeforge';
const tree = new TreeForge({
containerId: 'tree',
localData: myData
});
From Fancytree
// Fancytree (OLD)
$('#tree').fancytree({
source: myData
});
// TreeForge (NEW)
const tree = new TreeForge({
containerId: 'tree',
localData: myData,
...ConfigPresets.FILE_MANAGER
});
Key Differences
- ✅ No jQuery dependency
- ✅ Modern ES6+ syntax
- ✅ TypeScript support
- ✅ Better performance
- ✅ Mobile-first design
- ✅ Built-in themes and presets
Contributing
Help improve TreeForge
How to Contribute
- Fork the repository on GitHub
- Clone your fork locally
- Create a feature branch
- Make your changes
- Write tests for new features
- Commit with clear messages
- Push to your fork
- Open a pull request
Development Setup
# Clone the repository
git clone https://github.com/abmercy035/treeforge.git
cd treeforge
# Install dependencies
npm install
# Run development server
npm run dev
# Run tests
npm test
# Build for production
npm run build
Code Guidelines
- Follow the existing code style
- Write clear comments
- Add JSDoc for public APIs
- Keep functions small and focused
- Write unit tests for new features
- Update documentation
Reporting Issues
Found a bug? Have a feature request?
Open an Issue on GitHubSupport
Get help with TreeForge
Common Questions
Can I use TreeForge in commercial projects?
Yes! TreeForge is MIT licensed and free to use in any project.
Does TreeForge support TypeScript?
Yes, TreeForge includes TypeScript definitions.
Can I customize the styling?
Absolutely! Use CSS variables, custom classes, or the settings object.
Is TreeForge mobile-friendly?
Yes, TreeForge is fully responsive and touch-optimized.
Does TreeForge require jQuery?
No, TreeForge is pure vanilla JavaScript with zero dependencies.
Ready to Build Amazing File Trees?
Get started with TreeForge today and create beautiful, interactive file tree interfaces.