NotebookLM Enhancer
Source: Dev.to
Project Overview
A Chrome extension that transforms NotebookLM’s chaotic sidebar into a beautifully organized folder system, because 47 research notes shouldn’t look like a pile of digital laundry.
If you’ve used NotebookLM, you know it’s magical for research – upload PDFs, paste URLs, ask questions… it’s like having a research assistant that never sleeps. The only maddening catch? The sidebar becomes a nightmare when you have more than ten notes.
The Problem (Illustrated)
15 research papers on Spring Framework
8 articles about microservices
12 random bookmarks you saved “for later”
All. In. One. Giant. List.
No folders. No organization. Just… chaos.
Solution Overview
I built a Chrome extension that injects a complete folder‑management system directly into NotebookLM’s sidebar.
Smart Folder Organization
- Create folders and sub‑folders (1 level deep – keeping it simple)
- Drag & drop notes between folders with smooth animations
- “Inbox” view for unassigned notes
- Each notebook project has isolated folders (no cross‑contamination)
Polished UI that Matches NotebookLM
- Built with Angular + Tailwind CSS
- Dark / Light / System theme toggle
- Minimalist design that feels native
- Smooth expand / collapse animations
Internationalization
- Full i18n support (English / Spanish currently)
- One‑click language switcher
- All UI text translatable
Intelligent Integrations
- Click any note → opens native NotebookLM
- Click the three‑dots menu → native menu appears aligned to the right (matching native position)
- Drag notes from native sidebar → drop into our folders
- “Add new note” button that triggers native NotebookLM
Robust Architecture
- Chrome Extension MV3 (latest manifest version)
- Content scripts + Shadow DOM for style isolation
- Iframe‑based Angular app for the UI
postMessagebridge for iframe ↔ page communicationchrome.storage.syncfor persistence across devices
This isn’t a simple content script that adds a few buttons. It’s a full micro‑frontend architecture:
┌─────────────────────────────────────────────────────────┐
│ NotebookLM Page │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Native Sidebar (hidden but functional) │ │
│ │ • Still handles clicks & menus │ │
│ │ • We extract data from it │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Our Injected Host (Shadow DOM) │ │
│ │ ┌───────────────────────────────────────────┐ │ │
│ │ │ Iframe (Angular App) │ │ │
│ │ │ • Folder tree │ │ │
│ │ │ • Drag & drop (Angular CDK) │ │ │
│ │ │ • Theme toggle │ │ │
│ │ │ • Note add / folder add… │ │ │
│ │ │ • i18n │ │ │
│ │ └───────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Why an iframe inside Shadow DOM?
| Concern | Reason |
|---|---|
| Isolation | NotebookLM uses Angular Material with global styles; our iframe keeps Tailwind styles pristine |
| Security | Content scripts can’t easily access iframe internals (and vice‑versa) |
| Performance | Angular app runs independently without polluting the main page |
Communication Flow
- Content script reads native DOM → extracts notebook data
postMessage→ Angular displays organized folders- User drags note to folder →
postMessageback to content script - Content script updates
chrome.storage.sync
Technical Highlights
Storage V3 with Notebook Isolation
Instead of one global folder structure, each NotebookLM project gets its own isolated state:
// StorageStateV3
{
"byNotebook": {
"uuid-abc-123": {
"folders": [ /* … */ ],
"notebookFolderByKey": { /* … */ }
},
"uuid-def-456": {
"folders": [ /* … */ ],
"notebookFolderByKey": { /* … */ }
}
}
}
This means your “Work” folder structure doesn’t leak into your “Personal” research. Clean separation.
Handling MV3 Service Worker Sleep
Chrome MV3 Service Workers sleep after 30 seconds of inactivity, breaking chrome.runtime calls.
Instead of “keep‑alive” hacks we:
- Detect context invalidation gracefully
- Silently retry on the next frame
- Log to our own
NLE.log()instead of spammingconsole.warn
Native Drag Bridge
Making the native NotebookLM sidebar items draggable was tricky. We:
- Hook
dragstarton native items - Create an invisible overlay above our iframe during drag
- Calculate drop target using
elementFromPoint()with coordinates
Result: Native notes can be dropped into our folders seamlessly.
Auto‑Focus Input in Modals
Small UX detail that makes a huge difference:
- Create folder → input already focused, ready to type
- Rename folder → text is pre‑selected, just type to replace
- No extra clicks needed
Before / After
Before (no focus)
After (auto‑focus)
(Insert screenshots here if desired)
Demo
- Full video: (link or embed placeholder)
My Experience with GitHub Copilot CLI
This project was built almost entirely through GitHub Copilot CLI interactions, turning natural language into production‑ready code.
Architecture Decisions
# Asked Copilot: "Best way to inject UI into an existing Angular Material page?"
# Copilot suggested: Shadow DOM + iframe for isolation
# Result: Zero style conflicts with NotebookLM's Material Design
Content Script Structure
# Asked: "How to structure 8 content scripts that share state?"
# Copilot proposed: Module pattern with window.__NLE__ namespace
# Result: Clean separation, no global pollution
Drag & Drop Implementation
# Asked: "Bridge native HTML5 drag with Angular CDK drop?"
# Copilot designed: Overlay system with postMessage bridging
(Further prompts and iterations omitted for brevity.)
Closing Thoughts
“NotebookLM Enhancer” demonstrates how a well‑architected Chrome extension can turn a chaotic research workflow into a tidy, productive experience, all while leveraging modern web technologies (Angular, Tailwind, MV3) and the power of GitHub Copilot CLI.
Feel free to explore the repository, try the extension, and let me know what you think!
Coordinate Translation
Result: Seamless drag from native sidebar to our folders
Debugging Context Invalidation
Asked: “Chrome MV3 extension context invalidated errors?”
Copilot implemented: Graceful detection + silent retry logic
Result: No console spam, smooth recovery
i18n System
Asked: “Lightweight i18n without ngx‑translate bloat?”
Copilot built: Custom TranslationService with lazy loading
Result: ~3 KB vs ~50 KB, full interpolation support
Highlights
- Speed – What would have taken weeks took days. Complex features like the drag bridge were implemented in hours, not days.
- Architecture – Copilot suggested patterns I wouldn’t have considered (e.g., the iframe‑in‑shadow approach) that solved isolation problems elegantly.
- Edge Cases – MV3 quirks, Material Design menu positioning, SPA navigation detection – Copilot handled these gracefully.
- Learning – Every interaction was a learning moment 🙂. I now understand Chrome Extension architecture, Angular standalone components, and Tailwind customization.
Upcoming Features
- Chrome Web Store Launch – Polish, package, publish
- More Languages – French, German, Portuguese (easy with our i18n system)
- Search & Filter – Find notes within folders instantly
- Keyboard Shortcuts – Power‑user features (e.g.,
Ctrl+Shift+Nfor new folder)
🤝 Open Source
This project will be open‑sourced. Want to contribute?
- PRs welcome
- Good first issues: translations, themes, documentation
Resources & Credits
- Google for NotebookLM – an incredible research tool
- GitHub Copilot CLI – turning ideas into code faster than ever <3
- Tailwind CSS – making dark mode trivial
- DEV.to – hosting this challenge and bringing the community together
GitHub Repository
Built with ❤️ and a lot of help from GitHub Copilot CLI.
devchallenge
githubchallenge
cli
githubcopilot