A modern, lightweight browser extension template for Chrome and Firefox.
Built with Vite, Preact, TypeScript, and Tailwind CSS v4.
Like this template? Give it a ⭐ to show your support and help others discover it!
This template powers WebCheck360 — a full-featured SEO analysis extension that ships at just ~150KB. That makes it one of the smallest and fastest extensions in its category.
If you need a production-ready foundation that stays lean, this is it.
@/)git clone https://github.com/stephencovell/web-extension-template.git
cd web-extension-template
pnpm install
Edit project.json:
{
"name": "my-extension",
"extension": {
"name": "My Browser Extension",
"description": "Your extension description.",
"permissions": ["activeTab", "scripting", "storage"],
"firefox": {
"id": "[email protected]"
}
}
}
pnpm dev # Build to dist/
pnpm dev:watch # Watch mode - rebuilds on changes
Chrome:
chrome://extensions/dist/Firefox:
about:debugging#/runtime/this-firefoxdist/manifest.jsonpnpm build # Chrome zip
pnpm build:firefox # Firefox zip
pnpm build:all # Both
Output: artifact/my-extension-chrome-v1.0.0.zip
├── popup.html # Extension popup entry
├── project.json # Extension config (name, permissions, etc.)
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript configuration
├── src/
│ ├── popup.tsx # Popup mount point
│ ├── background.ts # Service worker
│ ├── content.ts # Content script
│ ├── tailwind.css # Tailwind + CSS variables
│ ├── components/
│ │ ├── Popup.tsx # Main popup component
│ │ └── ui/ # Reusable UI primitives
│ │ ├── Button.tsx
│ │ ├── Card.tsx
│ │ └── Input.tsx
│ ├── features/
│ │ └── todo/ # Example feature
│ │ ├── TodoList.tsx
│ │ └── TodoItem.tsx
│ ├── hooks/
│ │ └── useTodos.ts # Example custom hook
│ ├── types/
│ │ └── todo.ts # TypeScript types
│ └── utils/
│ └── cn.ts # Class name utility
├── public/
│ └── icons/ # Extension icons (16, 32, 48, 128px)
├── scripts/
│ └── build-extension.js # Build script
└── assets/
└── demo.png # Demo screenshot
Use @/ for clean imports:
import { Button } from '@/components/ui/Button'
import { cn } from '@/utils/cn'
Lucide icons are included:
import { Check, X, Plus } from 'lucide-preact'
<Button><Plus class="w-4 h-4" /> Add</Button>
CSS variables in src/tailwind.css:
@theme {
--color-background: hsl(0 0% 100%);
--color-primary: hsl(222 47% 11%);
}
.dark {
--color-background: hsl(222 47% 11%);
}
Replace icons in public/icons/:
| File | Size | Usage |
|---|---|---|
icon16.png |
16x16 | Toolbar |
icon32.png |
32x32 | Windows |
icon48.png |
48x48 | Extensions page |
icon128.png |
128x128 | Chrome Web Store |
Found a bug or have a suggestion? Open an issue or submit a PR.
If this template helped you, please consider giving it a ⭐!
MIT