Keyboard-driven Chrome extension for tab and Tab Group management. Built for power users who want vim-style navigation, session save/restore, tab cleanup tools, and Obsidian markdown export.
Screenshots coming soon.
- Vim-style navigation —
j/kto move,ddto close,yy/pto yank/paste URLs,/to search,Vfor visual selection,:commands - Tab tree — virtualized list of all open tabs across windows, grouped by Tab Groups
- Sessions — save and restore window/tab/group snapshots with one command
- Tab cleanup — find and remove duplicate tabs, sort tabs by title/domain/URL, with quick-access action bar
- Cleanup rules — configurable rules that auto-close, pin, mute, or group tabs matching patterns
- Obsidian export — copy tabs as markdown, download
.md, or open directly in Obsidian via deep link - Resizable popup — drag the bottom-right corner to resize; works in both normal and pinned popup modes
- Live preferences — runtime settings control favicons, vim keybindings, close confirmations, and badge tab counts
Requires Node.js 18+ and pnpm.
git clone https://github.com/mjacobs/tabz.git
cd tabz
pnpm install
pnpm devThen load the extension in Chrome:
- Open
chrome://extensions - Enable Developer mode (top-right toggle)
- Click Load unpacked
- Select the
.output/chrome-mv3-dev/directory
The extension will live-reload as you edit source files.
pnpm buildLoad the unpacked extension from .output/chrome-mv3/ using the same steps above.
pnpm test # Run tests (vitest)
pnpm typecheck # TypeScript check (tsc --noEmit)
pnpm lint # ESLint
pnpm format # PrettierOpen the popup with Alt+T (configurable in chrome://extensions/shortcuts).
| Key | Action |
|---|---|
j / k |
Move cursor down/up |
gg / G |
Jump to top/bottom |
Ctrl+d / Ctrl+u |
Half-page down/up |
Enter |
Activate (switch to) tab |
Space |
Toggle group collapse |
dd |
Close tab under cursor |
yy |
Yank tab URL to clipboard |
p |
Open yanked URLs as new tabs |
r |
Rename group under cursor |
/ |
Start search |
n / N |
Next/previous search match |
V |
Enter visual mode |
: |
Enter command mode |
? |
Toggle help overlay |
1-9 |
Count prefix (e.g. 5j moves 5 rows) |
| Key | Action |
|---|---|
j / k |
Extend selection |
d |
Close selected tabs |
y |
Yank selected tab URLs |
Escape |
Exit visual mode |
| Command | Action |
|---|---|
:sort [key] |
Sort tabs (title, domain, url) |
:dedup |
Remove duplicate tabs |
:group Name |
Group visual selection under Name |
:save Name |
Save current session |
:sessions |
Switch to sessions panel |
:tabs |
Switch to tabs panel |
:cleanup |
Switch to cleanup panel |
:q |
Close popup |
| Layer | Technology |
|---|---|
| Build | WXT 0.20 (Vite, Manifest V3) |
| UI | React 19 |
| State | Zustand 5 |
| CSS | Tailwind CSS 4 |
| Virtualization | @tanstack/react-virtual |
| Testing | Vitest + Testing Library |
| Lint/Format | ESLint 9 + Prettier |
All business logic lives in src/engine/ as pure functions with no React or Chrome UI dependencies. The UI layer is thin:
Popup (React) -> Zustand Stores -> chrome.runtime.sendMessage -> Background Worker -> Engine
See CLAUDE.md for detailed file structure and implementation notes.
- tabs — read tab URLs, titles, and state
- tabGroups — manage Tab Groups (create, rename, collapse)
- storage — persist sessions, rules, and preferences
- alarms — schedule auto-save intervals
MIT