A browser extension for hierarchical tab management with a tree-based interface.
Started as an experiment with IndexedDB syncing for TanStack collections,
grew into a tool I actually use daily. Rough edges expected—contributions welcome!
demo.mp4
See Tab Canopy in action - tree-based organization, drag & drop, and real-time sync.
🚧 Alpha Quality - This is an experimental project that started as a playground for IndexedDB syncing patterns with TanStack collections. It evolved into a functional tab manager that I use daily, but there are many rough edges and missing features.
Help Wanted! This project needs contributors to:
- Review security (see SECURITY.md - especially the extension messaging concerns)
- Implement missing features (see TODO.md)
- Fix bugs and improve UX
- Test on different browsers and setups
If you're interested in browser extension development, React, or database syncing patterns, this is a great project to explore!
- Tree-based Tab Organization: Organize tabs in a hierarchical tree structure with parent-child relationships
- Smart Search: Fuzzy search (Ctrl+F) that handles typos and maintains tree context - parent tabs stay visible when children match
- Drag & Drop Interface: Intuitive drag-and-drop reordering and nesting of tabs
- Side Panel UI: Clean, accessible side panel interface built with React
- Persistent Storage: IndexedDB-backed storage with Drizzle ORM for reliable data persistence
- Real-time Sync: Automatic synchronization between browser tab events and UI state
- Developer Tools: Built-in dev tools panel for debugging and state inspection
- Multi-browser Support: Compatible with Chrome and Firefox
See TODO.md for the roadmap of planned features and improvements.
Once installed, using Tab Canopy is simple:
- Open the side panel - Click the Tab Canopy icon in your browser toolbar
- View your tabs - All open tabs appear in the side panel organized by window
- Navigate - Click any tab to switch to it
- Organize with drag & drop:
- Drag a tab up or down to reorder it
- Drag a tab onto another tab to make it a child (nested)
- Drag a tab to the left to un-nest it
- Search tabs - Press
Ctrl+Fto search through all tabs with fuzzy matching (handles typos!) - Collapse/expand branches - Click the arrow icon next to parent tabs
- Multi-level nesting - Create deep hierarchies to organize complex research or projects
- Visual tree lines - Lines show parent-child relationships at a glance
- Right-click for options - Context menu with additional actions for tabs and windows
- Real-time updates - Changes sync instantly with your browser tabs
Organizing a research project:
Research: React Server Components
├── Official RFC
├── Tutorials
│ ├── Building with RSC
│ └── Migration Guide
└── Examples
├── Next.js App
└── Remix Implementation
Simply drag tabs to create this structure - Tab Canopy remembers your organization!
- Framework: WXT - Modern WebExtension framework
- UI: React 19 + TailwindCSS 4
- State Management: Jotai
- Database: IndexedDB with Drizzle ORM
- Drag & Drop: @dnd-kit
- Build System: Turborepo + Bun
- Testing: Playwright (E2E) + Bun Test (Unit)
- Code Quality: Biome
Tab Canopy is currently in alpha and is not available on the Chrome Web Store or Firefox Add-ons. You need to install it manually from source.
Requirements:
- Bun 1.3.3 or higher
- Basic comfort with command line
Steps:
- Clone and build the extension:
git clone https://github.com/firtoz/tab-canopy.git
cd tab-canopy
bun install
bun build # for Chrome
# OR
bun build:firefox # for Firefox- Load into your browser:
Chrome:
- Open
chrome://extensions/ - Enable "Developer mode" (toggle in top-right)
- Click "Load unpacked"
- Select the
.output/chrome-mv3directory
Firefox:
- Open
about:debugging#/runtime/this-firefox - Click "Load Temporary Add-on"
- Select any file in
.output/firefox-mv2directory
Note: Firefox temporary extensions are removed when the browser closes. You'll need to reload it each time.
See CONTRIBUTING.md for development setup instructions.
tabcanopy/
├── packages/
│ ├── extension/ # Browser extension package
│ │ ├── entrypoints/
│ │ │ ├── background/ # Service worker (MV3)
│ │ │ ├── sidepanel/ # Side panel React app
│ │ │ └── content.ts # Content script
│ │ ├── schema/ # Drizzle ORM schema & migrations
│ │ └── src/ # Shared utilities
│ └── e2e-tests/ # Playwright E2E tests
└── package.json # Monorepo root
Want to contribute? See CONTRIBUTING.md for full setup instructions.
# Install dependencies
bun install
# Start development server with hot reload
bun dev # Chrome
bun dev:firefox # Firefox
# Load from .output/chrome-mv3-dev or .output/firefox-mv2-dev- Bun 1.3.3 or higher
- Node.js (for Playwright)
# Run all tests
bun test
# Unit tests only
bun test:unit
# E2E tests (builds extension first)
bun test:e2e
bun test:e2e:ui # With Playwright UI
bun test:e2e:headed # With browser visible
# E2E tests in dev mode (uses dev build)
bun test:e2e:dev
bun test:e2e:dev:ui # With Playwright UI
bun test:e2e:dev:headed # With browser visible# Lint and auto-fix
bun lint
# Lint for CI (no auto-fix)
bun lint:ci
# Format code
bun format
# Type check
bun typecheck# Generate migrations (after schema changes)
bun db:generate- Listens to browser tab and window events
- Maintains sync between browser state and IndexedDB
- Implements IDB proxy server for multi-client access
- Handles initial sync on extension load
- React-based interface with real-time updates
- Drag-and-drop tab reordering with tree nesting
- Uses IndexedDB proxy client for database access
- Move intent system prevents race conditions during drag operations
windows: Browser window metadatatabs: Tab information with tree structure (parentTabId,treeOrder)- Uses fractional indexing for efficient reordering
- Background service worker is the single source of truth
- UI connects via IDB proxy transport over Chrome messaging
- Broadcast system keeps all clients in sync
- Move intents allow UI to declare pending operations
Tab Canopy uses Changesets for automated versioning and publishing:
- Make changes →
bun changeset→ Describe changes - Push to main → GitHub Actions creates "Version Packages" PR
- Merge PR → Automatically uploads to Chrome Web Store as draft
- Manually publish from developer dashboard
See docs/RELEASING.md for the complete workflow guide.
For initial setup instructions, see docs/PUBLISHING.md.
We welcome contributions! See CONTRIBUTING.md for detailed instructions.
Quick summary:
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting:
bun test && bun lint - Submit a pull request
MIT License - see LICENSE for details.
- Background logs: Right-click extension icon → "Manage Extension" → "Inspect views: service worker"
- Side panel logs: Open side panel → Right-click → "Inspect"
The extension includes built-in dev tools:
- Click the dev tools toggle in the side panel
- View recorded events and replay them
- Inspect current database state
WXT provides automatic hot reload during development:
- Content scripts: Automatically reloaded
- Background: Automatically restarted
- UI: React Fast Refresh for instant updates
- Check browser console for errors
- Ensure you're loading from the correct output directory
- Try removing and re-adding the extension
- Open dev tools panel and reset database
- Check background service worker console for migration errors
- Clear node_modules and reinstall:
rm -rf node_modules bun.lock && bun install - Check Bun version:
bun --version(should be 1.3.3+)