StyleGrabber is a high-performance, cross-browser web extension (built with WXT, React, TypeScript, and Vite) that allows developers, designers, and UI engineers to instantly inspect, diff, extract, and copy element styles and HTML subtrees directly from any webpage.
Unlike default browser DevTools which require inspecting deep DOM trees and sifting through raw computed style lists, StyleGrabber provides an interactive on-page hover overlay, dynamic computed style diffing against browser defaults, authoring stylesheet cascade resolution, CSS custom property (var()) resolution, pseudo-element (::before/::after) extraction, tree-mode DOM sub-tree capturing, and auto-copying formatted code directly to your clipboard.
Hover over any web element to see a GPU-accelerated bounding box, tag/class badge, and live floating preview panel displaying non-default CSS computed properties, color swatches, resolved variables, pseudo-elements, and matched rule counts.
Easily toggle extension state, pin overlays for detailed examination, enable DOM Tree Subtree Mode, toggle Auto-Copy on hover dwell, select clipboard output templates (HTML + CSS, CSS Only, HTML Only), customize keyboard shortcuts (Alt+Shift+P / ^+Shift+P), adjust inactivity timeouts, and switch theme modes (Light, Dark).
- ⚡ 60fps GPU-Composited Mouse Tracking: Repositioning uses
requestAnimationFramebatching and CSStranslate3d()transforms for jitter-free performance on heavy pages. - 🎨 Dynamic Baseline Computed Style Diffing: Compares target element styles against an isolated tag default iframe baseline table to extract only authored/custom styles, omitting default browser styles and redundant parent inherited values.
- 🔍 Authoring Rule Cascade & CSS Variables: Walks accessible
document.styleSheetsin cascade order, resolves nestedvar(--x)chains up to depth 10 with circular reference protection, and displays exact CSS declarations. - ✨ Pseudo-Element Extraction: Automatically detects and diffs non-default styles for
::beforeand::afterpseudo-elements. - 🌲 Single Element & Tree Mode Traversal: Generator-based non-blocking DOM walker with recursion depth limit (
maxDepth: 15) and node cap (maxNodes: 5000) to snapshot entire component subtrees smoothly on complex SPAs. - 📋 Formatted Clipboard Export: Generates clean, pretty-printed HTML structure and categorized CSS declarations grouped by Layout, Typography, Box Model, Background, Border, and Effects.
- 🛡️ Shadow DOM UI Shell: Complete CSS isolation using WXT's
createShadowRootUi()ensures target page styles never leak into the extension overlay and vice versa. - 📌 Pinning & Inactivity Fade: Press shortcut or click to pin overlay target for inspection, or allow auto-fade after 5 seconds of cursor inactivity.
- 🎯 Viewport Collision Avoidance: 4-way boundary math shifts floating tooltips dynamically to remain fully visible near screen edges.
- 🔒 Context Invalidation Guards: Robust error handling prevents runtime crashes when extension is updated or reloaded while tabs remain open.
- 🧹 WeakMap Memory Hardening: Uses
WeakMapcaches and element connection checks (isConnected) to ensure unmounted DOM nodes are immediately garbage collected.
StyleGrabber follows WXT's convention-over-configuration architecture with strict module boundary rules:
StyleGrabber/
├── entrypoints/
│ ├── background.ts # MV3 Service worker (lifecycle & storage init)
│ ├── content/
│ │ ├── index.ts # Content script entry (defineContentScript)
│ │ └── mountUi.tsx # Shadow DOM mount point (createShadowRootUi)
│ └── popup/
│ ├── App.tsx # Popup options & settings UI (React)
│ └── style.css # Popup styling & theme custom properties
│
├── components/ # Shadow-DOM isolated UI components
│ ├── ContentApp.tsx # Main content script overlay orchestration
│ ├── HoverBox.tsx # Animated bounding box overlay
│ ├── Badge.tsx # Tag + class label pill with copied toast feedback
│ ├── Tooltip.tsx # Syntax-highlighted CSS preview panel
│ └── shared/
│ ├── theme.css # Scoped CSS custom properties (:host)
│ └── Icon.tsx # Inline SVG icons (Copy, Check, Pin, etc.)
│
├── utils/
│ ├── style-engine/ # ⚙️ CORE MODULE 1 — Style Extraction
│ │ ├── computeDiff.ts # Computed style vs UA baseline table diffing
│ │ ├── baseline.ts # Detached iframe tag baseline generator
│ │ ├── ruleMatcher.ts # Stylesheet cascade rule & @media matching
│ │ ├── pseudoElements.ts # ::before / ::after style extraction
│ │ ├── cssVariableResolver.ts # Resolves nested var(--x) chains & circular refs
│ │ └── properties.ts # Categorized CSS property matrices
│ │
│ ├── dom-traversal/ # ⚙️ CORE MODULE 2 — DOM Walking
│ │ ├── traverse.ts # Single node vs recursive generator walk
│ │ ├── elementFilter.ts # Filters script/style/hidden/overlay elements
│ │ └── domSnapshot.ts # Builds serializable DOM node snapshots
│ │
│ ├── formatter/ # ⚙️ CORE MODULE 3 — Output Formatting
│ │ ├── htmlFormatter.ts # Pretty-prints HTML structure block
│ │ ├── cssFormatter.ts # Indents/groups CSS declarations & deduplicates
│ │ └── clipboardComposer.ts # Assembles HTML + CSS export payloads
│ │
│ ├── shadow-dom/ # ⚙️ CORE MODULE 4 — UI Isolation
│ │ ├── mountUi.tsx # Shadow root launcher & React renderer
│ │ └── positioning.ts # Viewport-aware 4-way collision positioning
│ │
│ ├── storage/ # ⚙️ STORAGE & SETTINGS
│ │ ├── schema.ts # Typed Zod/Valibot-like settings schema
│ │ └── settings.ts # browser.storage.local wrapper w/ live sync
│ │
│ └── perf/ # ⚙️ PERFORMANCE & HARDENING
│ └── raf-throttle.ts # requestAnimationFrame event throttling
│
├── public/
│ ├── icon/ # Extension icons (16, 32, 48, 96, 128 px)
│ └── icon.png # Main high-res extension icon
│
├── wxt.config.ts # WXT configuration & manifest declaration
├── package.json
└── tsconfig.json
| Module | Responsibility | Must NOT Depend On |
|---|---|---|
style-engine/ |
Pure style extraction logic (element → resolved styles) | DOM mounting, React, Storage |
dom-traversal/ |
Pure DOM tree walking & node filtering | style-engine, formatter |
formatter/ |
Pure string formatting & payload assembly | Live DOM APIs directly |
shadow-dom/ |
Mounting overlay & viewport positioning | style-engine internals |
components/ |
Presentation UI rendered inside Shadow Root | Direct document.styleSheets calls |
- Node.js:
≥ 18.0.0 - Package Manager:
pnpm(recommended),npm, oryarn
-
Clone the repository:
git clone https://github.com/kapaggar/StyleGrabber.git cd StyleGrabber -
Install dependencies:
pnpm install
Launch the dev server with automatic hot-reloading and automatic browser instance launch:
# Launch Chrome / Edge dev environment
pnpm dev
# Launch Firefox dev environment
pnpm dev:firefox- Run
pnpm build(outputs to.output/chrome-mv3/). - Open Chrome and navigate to
chrome://extensions/. - Enable Developer mode in the top right corner.
- Click Load unpacked and select the
.output/chrome-mv3/directory.
- Run
pnpm build:firefox(outputs to.output/firefox-mv3/). - Open Firefox and navigate to
about:debugging#/runtime/this-firefox. - Click Load Temporary Add-on... and select the
manifest.jsonfile inside.output/firefox-mv3/.
StyleGrabber maintains high code quality with automated unit testing:
# Run all unit tests with Vitest (jsdom environment)
pnpm test
# Run TypeScript type check
pnpm typecheck
# Run ESLint validation
pnpm lintGenerate store-ready .zip archives for Chrome Web Store and Firefox Add-ons (AMO):
# Package Chrome zip archive (.output/stylegrabber-<version>-chrome.zip)
pnpm zip
# Package Firefox zip archive (.output/stylegrabber-<version>-firefox.zip & sources.zip)
pnpm zip:firefox
# Full pre-publish gate (test + typecheck + lint + zip)
pnpm prepublish:checkThis repo includes listing copy, permission justifications, and a step-by-step checklist:
| Resource | Path |
|---|---|
| Publish checklist | docs/CHROME_WEB_STORE.md |
| Store listing text | store/listing.md |
| Permission justifications | store/permissions.md |
| Screenshot size guide | store/SCREENSHOTS.md |
| Privacy policy | PRIVACY_POLICY.md |
Before first CWS submit: capture screenshots at 1280×800 or 640×400 (see screenshot guide). Existing assets/images/* files are for the README and are not yet store-sized.
| Script | Command | Description |
|---|---|---|
pnpm dev |
wxt |
Start WXT development server for Chromium |
pnpm dev:firefox |
wxt -b firefox |
Start WXT development server for Firefox |
pnpm build |
wxt build |
Build production Chromium MV3 bundle |
pnpm build:firefox |
wxt build -b firefox |
Build production Firefox MV3 bundle |
pnpm test |
vitest run --environment jsdom |
Execute Vitest unit test suite |
pnpm typecheck |
tsc --noEmit |
Check TypeScript compilation without emitting |
pnpm lint |
eslint . |
Lint TypeScript code against project rules |
pnpm zip |
wxt zip |
Package Chrome zip archive for distribution |
pnpm zip:firefox |
wxt zip -b firefox |
Package Firefox zip archive for distribution |
pnpm prepublish:check |
tests + lint + zip | Gate before Chrome Web Store upload |
- Problem: Reading
sheet.cssRuleson cross-origin<link>stylesheets (e.g., Google Fonts, CDN FontAwesome) throws aSecurityError. - Solution: StyleGrabber's computed style diffing engine reads the live render tree via
getComputedStyle(), which is CORS-immune. CSS rule matching wraps sheet accesses intry/catchand displays a graceful notice when stylesheet rule source access is blocked.
- Problem: Updating/reloading an extension in development while web pages remain open invalidates the extension context, causing
Extension context invalidatederrors when calling storage APIs. - Solution: Guarded runtime checks (
isExtensionContextValid()) andtry/catchwrappers around all storage calls ensure smooth operation without unhandled promise rejections.
- Problem: Inspecting dynamic single-page applications (React, Next.js, Vue) can leak DOM references.
- Solution: Snapshot caches use
WeakMap<Element, DomNodeSnapshot>, elements are verified for active document connection (isConnected), and keyboard/SPA route event listeners (popstate/hashchange) clean up unmounted nodes.
See CONTRIBUTING.md. Agent-oriented project maps: CLAUDE.md, AGENTS.md.
StyleGrabber processes styles locally only and does not collect personal data.
- Policy (Markdown):
PRIVACY_POLICY.md - Policy (public site): https://kapaggar.github.io/StyleGrabber/privacy.html
- Project site: https://kapaggar.github.io/StyleGrabber/
This project is licensed under the MIT License. See the LICENSE file for details.



