From tenequm-skills
Build Chrome extensions using WXT framework with TypeScript, React, Vue, or Svelte. Useful for creating browser extensions, cross-browser add-ons, and Manifest V3 projects.
How this skill is triggered — by the user, by Claude, or both
Slash command
/tenequm-skills:chrome-extension-wxtThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build modern, cross-browser extensions using WXT - the next-generation framework that supports Chrome, Firefox, Edge, Safari, and all Chromium browsers with a single codebase.
Build modern, cross-browser extensions using WXT - the next-generation framework that supports Chrome, Firefox, Edge, Safari, and all Chromium browsers with a single codebase.
Use this skill when:
# Create new project with framework of choice
npm create wxt@latest
# Or with specific template
npm create wxt@latest -- --template react-ts
npm create wxt@latest -- --template vue-ts
npm create wxt@latest -- --template svelte-ts
WXT uses file-based conventions:
project/
├── entrypoints/ # Auto-discovered entry points
│ ├── background.ts # Service worker
│ ├── content.ts # Content script
│ ├── popup.html # Popup UI
│ └── options.html # Options page
├── components/ # Auto-imported UI components
├── utils/ # Auto-imported utilities
├── public/ # Static assets
│ └── icon/ # Extension icons
├── wxt.config.ts # Configuration
└── package.json
npm run dev # Start dev server with HMR
npm run build # Production build
npm run zip # Package for store submission
WXT recognizes entry points by filename in entrypoints/ directory:
// entrypoints/background.ts
export default defineBackground({
type: 'module',
persistent: false,
main() {
// Listen for extension events
browser.action.onClicked.addListener((tab) => {
console.log('Extension clicked', tab);
});
// Handle messages
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Handle message
sendResponse({ success: true });
return true; // Keep channel open for async
});
},
});
// entrypoints/content.ts
export default defineContentScript({
matches: ['*://*.example.com/*'],
runAt: 'document_end',
main(ctx) {
// Content script logic
console.log('Content script loaded');
// Create UI
const ui = createShadowRootUi(ctx, {
name: 'my-extension-ui',
position: 'inline',
anchor: 'body',
onMount(container) {
// Mount React/Vue component
const root = ReactDOM.createRoot(container);
root.render(<App />);
},
});
ui.mount();
},
});
// entrypoints/popup/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<!-- entrypoints/popup/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Extension Popup</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
import { defineConfig } from 'wxt';
export default defineConfig({
// Framework integration
modules: ['@wxt-dev/module-react'],
// Manifest configuration
manifest: {
name: 'My Extension',
description: 'Extension description',
permissions: ['storage', 'activeTab'],
host_permissions: ['*://example.com/*'],
},
// Browser target
browser: 'chrome', // or 'firefox', 'edge', 'safari'
});
// utils/storage.ts
import { storage } from 'wxt/storage';
export const storageHelper = {
async get<T>(key: string): Promise<T | null> {
return await storage.getItem<T>(`local:${key}`);
},
async set<T>(key: string, value: T): Promise<void> {
await storage.setItem(`local:${key}`, value);
},
watch<T>(key: string, callback: (newValue: T | null) => void) {
return storage.watch<T>(`local:${key}`, callback);
},
};
// utils/messaging.ts
interface Messages {
'get-data': {
request: { key: string };
response: { value: any };
};
}
export async function sendMessage<K extends keyof Messages>(
type: K,
payload: Messages[K]['request']
): Promise<Messages[K]['response']> {
return await browser.runtime.sendMessage({ type, payload });
}
// Inject script into page context
import { injectScript } from 'wxt/client';
await injectScript('/injected.js', {
keepInDom: false,
});
# Build for specific browser
npm run build -- --browser=chrome
npm run build -- --browser=firefox
# Create store-ready ZIP
npm run zip
npm run zip -- --browser=firefox
# Build for all browsers
npm run zip:all
Output: .output/my-extension-{version}-{browser}.zip
Popular technology combinations for building Chrome extensions:
Most popular stack in 2025. Combines utility-first styling with pre-built accessible components.
npm create wxt@latest -- --template react-ts
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
npx shadcn@latest init
Best for: Modern UIs with consistent design system Example: https://github.com/imtiger/wxt-react-shadcn-tailwindcss-chrome-extension
Complete component library with 100+ components and built-in dark mode.
npm create wxt@latest -- --template react-ts
npm install @mantine/core @mantine/hooks
Best for: Feature-rich extensions needing complex components Example: https://github.com/ongkay/WXT-Mantine-Tailwind-Browser-Extension
Clean setup for custom designs without UI library dependencies.
npm create wxt@latest -- --template react-ts
Best for: Simple extensions or highly custom designs
For detailed information on advanced topics, see the reference files:
references/react-integration.md for complete React setup, hooks, state management, and popular UI librariesreferences/chrome-api.md for comprehensive Chrome Extension API reference with examplesreferences/chrome-140-features.md for latest Chrome Extension APIs (sidePanel.getLayout(), etc.)references/wxt-api.md for complete WXT framework API documentationreferences/best-practices.md for security, performance, and architecture patternsCommon issues and solutions:
content_security_policy in manifeststorage.local or storage.sync correctlyFor detailed troubleshooting, see references/troubleshooting.md
Use these resources as needed when building your extension.
npx claudepluginhub tenequm/skillsScaffolds and maintains browser extensions with Vue 3, Vite, and the Vitesse WebExtension template. Covers popup, options, sidepanel, content script, and multi-entry build for Chrome/Firefox.
Builds Chrome, Firefox, and cross-browser extensions with Manifest V3, content scripts, popup UIs, and store publishing guidance.
Configures CRXJS Vite plugin for Chrome extensions with HMR for popups, options, content scripts, side panels, dynamic imports, and type-safe manifests.