Overview
This standard covers browser extension development — primarily Chrome extensions using Manifest V3. Extensions have unique constraints: strict permission models, content security policies, store review processes, and cross-version compatibility.
Prerequisites: General Standards (file structures, Git, a11y, privacy).
What this covers:
- Chrome extensions (Manifest V3)
- Cross-browser extensions (Chrome + Firefox + Edge)
- Companion web dashboards (paired extensions)
- Store listing optimization
Tech Stack (2026)
| Layer | Primary | Alternative |
|---|---|---|
| Framework | WXT + Svelte 5 | WXT + Preact for React developers |
| Language | TypeScript 5.9 (strict) | — |
| Styling | Tailwind CSS | Shadow DOM + CSS (isolated UIs) |
| Build | WXT (Vite under the hood) | Plasmo Framework |
| State | Svelte stores / Nanostores | — |
| Dashboard (paired web app) | Next.js 16 + Prisma + Stripe | — |
| Testing | Vitest (unit) + Playwright (E2E with Chrome headless) | — |
Why WXT over alternatives:
- First-class Manifest V3 support
- Auto-generated
manifest.jsonfrom config - Built-in HMR for extension development (popup, options, content scripts)
- Cross-browser builds from a single codebase
- Active community and frequent updates
Why Svelte 5:
- Minimal runtime overhead (adds ~2KB to extension bundle)
- Runes-based reactivity eliminates complex state management for most use cases
- Compiled output (no virtual DOM) — critical for performance-constrained extension environments
Project Scaffolding
File Structure (WXT + Svelte)
project-root/
├── src/
│ ├── entrypoints/
│ │ ├── popup/ # Extension popup UI
│ │ │ ├── App.svelte
│ │ │ ├── index.html
│ │ │ └── style.css
│ │ ├── options/ # Options/settings page
│ │ ├── background.ts # Service worker (MV3)
│ │ ├── content.ts # Content scripts (page injection)
│ │ └── sidepanel/ # Side panel (Chrome 114+)
│ ├── components/ # Shared UI components
│ ├── lib/
│ │ ├── api/ # External API clients (Gmail, X, etc.)
│ │ ├── storage/ # Chrome storage wrapper with types
│ │ ├── utils/ # Pure utilities
│ │ └── types/ # TypeScript types
│ └── assets/ # Icons, images
├── public/ # Static assets (not processed by build)
├── wxt.config.ts # WXT configuration
├── tsconfig.json
└── package.json
WXT Configuration Template
// wxt.config.ts
import { defineConfig } from 'wxt';
export default defineConfig({
manifest: {
name: 'My Extension',
version: '0.1.0',
description: 'Production-grade Chrome extension.',
permissions: ['storage', 'identity'],
host_permissions: ['https://api.example.com/*'],
action: {
default_popup: 'entrypoints/popup/index.html',
},
},
vite: () => ({
plugins: [],
}),
});
Initial Setup Checklist
-
npm create wxt@latestwith Svelte template - TypeScript strict mode
- Tailwind CSS configured for WXT
- Icon set created (16×16, 48×48, 128×128, optional 32×32)
-
manifest.jsonpermissions minimized to strict necessity - Content security policy (CSP) reviewed
-
.envstructure for API keys (if any)
Architecture & Design Patterns
Extension Architecture (Manifest V3)
Extension (WXT)
├── Service Worker (background.ts)
│ ├── Lifecycle: event-driven, terminates when idle
│ ├── Use: API proxying, alarms, messaging, state sync
│ ├── DON'T: DOM access, long-running computations
│ └── Persistence: chrome.storage.local/session (not global state)
│
├── Content Scripts (content.ts)
│ ├── Runs in page context (isolated world)
│ ├── Use: DOM manipulation, UI injection, page data extraction
│ ├── Messaging: chrome.runtime.sendMessage to service worker
│ └── Style: Shadow DOM to avoid conflicts with host page
│
├── Popup (popup/)
│ ├── Temporary UI (closes on focus loss)
│ ├── Keep lightweight — fetch heavy data from background
│ └── Max size: 600×600 recommendation
│
└── Options Page (options/)
├── Persistent settings interface
├── User preferences stored in chrome.storage.sync
└── Accessible via right-click → Options or extension management
Communication Flow
Content Script → (chrome.runtime.sendMessage) → Service Worker
↓
Service Worker → (chrome.runtime.sendMessage) → Popup/Options
↓
Service Worker → (Fetch API) → External Server (if paired web app)
All communication is asynchronous. Use request/response patterns with unique IDs for tracking:
// content.ts
const response = await chrome.runtime.sendMessage({
type: 'FETCH_LABELS',
requestId: crypto.randomUUID(),
});
Permission Strategy
- Minimum viable permissions — Start with zero, add only what’s proven necessary
- Host permissions — Specific origins, not
<all_urls>unless absolutely required - ActiveTab — Use instead of broad host permissions when interaction only needs the current tab
- Storage — Use
chrome.storage.localfor large data,chrome.storage.syncfor settings (limited to 100KB) - Optional permissions — Request at runtime, not install time, for sensitive capabilities
Performance Standards
Extension-Specific Targets
| Metric | Target |
|---|---|
| Popup load time | ≤ 500ms (first paint) |
| Content script injection | ≤ 100ms after page load |
| Service worker wake time | ≤ 50ms |
| Background message latency | ≤ 20ms (same-process) |
| Bundle size (popup) | ≤ 100KB gzipped |
| Bundle size (content script) | ≤ 30KB gzipped |
Optimization Tactics
- Lazy content scripts — Use
"run_at": "document_idle"to avoid blocking page load - Service worker warmup — Use
chrome.alarmsto keep the service worker alive when needed - Efficient messaging — Batch messages where possible; avoid per-element message passing
- Minimal content script footprint — Inject only necessary DOM; prefer Shadow DOM for UI elements
- Static assets — Bundle icons inline as base64 for popup to avoid extra network requests
Chrome Web Store Compliance
Submission Checklist
- Privacy policy published at a public URL and linked in manifest
- Permissions — each permission justified in the store listing
- Data usage — clear disclosure of what data is collected and why
- Single purpose — extension does one well-defined thing
- Content security — no remote code execution (
eval(),new Function()) - Manifest V3 — MV2 is deprecated; all new submissions must be MV3
- Icons — 16×16, 48×48, 128×128 (required), 32×32 (recommended)
- Screenshots — 1280×800 or 640×400 minimum; show real functionality
- Promotional tile — 440×280 small tile, optional 920×680 large tile
- Description — clear, accurate, includes primary uses and limitations
Common Rejection Reasons
| Issue | Prevention |
|---|---|
| Insufficient permissions justification | In the store description, explain why each permission is needed |
| No privacy policy | Publish a privacy policy URL. Even if you collect nothing, state that. |
| Deceptive functionality | Don’t claim features the extension doesn’t perform |
| Low-quality UI | Follow platform design patterns; test on multiple pages/sites |
| Broken on submission | Test on a clean Chrome profile before submitting |
Review Timeline
- Initial review: 1–3 business days (new extensions)
- Updates: 1–2 business days
- Expedited review: Available for critical fixes (limited use)
- Appeals: 5–7 business days for policy violations
Review & Shipping Checklist
- All permissions justified and minimized
- Privacy policy published and linked in manifest
- Content security policy (CSP) reviewed — no remote code execution
- Service worker error handling: try/catch on all async operations
- Storage schema versioned for future migrations
- Icons created at all required sizes
- Screenshots captured (1280×800 minimum)
- Tested on a clean Chrome profile with no other extensions
- Cross-browser tested (Chrome + Firefox + Edge if applicable)
- Accessibility: popup navigable via keyboard, screen reader tested
- Offline behavior handled gracefully
- Error monitoring (if paired web app) configured
- Store listing description written with SEO keywords
Trends to Watch (2026+)
- Manifest V3 maturity — Service worker limitations addressed via improved APIs
- Side panel standard — Chrome 114+ side panel API enabling persistent UIs
- AI-powered extensions — On-device AI (Chrome built-in AI API) for content analysis without server calls
- Cross-browser standards — Manifest V3 converging across Chromium, Firefox, and Safari
- Declarative Net Request — Replacing
webRequestblocking for privacy and performance
Project Templates & Quick Starts
- LabelKit — Reference: WXT + Svelte 5 + Gmail API extension
- Xcelerate — Reference: Extension + Next.js 16 paired dashboard
References
- LabelKit project page — Real-world WXT extension architecture
- Xcelerate project page — Extension + web dashboard paired pattern
- Securing AI Developer Workflows — Security practices for development
- External: Chrome Extensions Documentation, WXT Documentation, Chrome Web Store Best Practices