Learn how to build a modern Chrome extension using React 19 and TypeScript. This step-by-step guide covers manifest v3, popup development, background scripts, and best practices for extension architecture.
Building browser extensions has evolved significantly with the introduction of Manifest V3. In this comprehensive guide, I'll walk you through creating a production-ready Chrome extension using React and TypeScript.
While Chrome extensions can be built with vanilla JavaScript, using React offers several advantages:
A well-organized Chrome extension typically follows this structure:
extension/
├── manifest.json
├── popup/
│ ├── index.html
│ ├── App.tsx
│ └── components/
├── background/
│ └── service-worker.ts
├── content/
│ └── content-script.ts
└── options/
├── index.html
└── Options.tsx
With Manifest V3, the manifest.json has some important changes:
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"background": {
"service_worker": "background.js",
"type": "module"
},
"permissions": ["storage", "tabs"]
}
The popup is where users interact with your extension. Here's a simple React component:
import { useState, useEffect } from 'react';
export default function Popup() {
const [data, setData] = useState<string>('');
useEffect(() => {
// Load saved data from chrome.storage
chrome.storage.local.get(['savedData'], (result) => {
if (result.savedData) {
setData(result.savedData);
}
});
}, []);
const handleSave = () => {
chrome.storage.local.set({ savedData: data });
};
return (
<div className="p-4 w-80">
<h1 className="text-lg font-bold">My Extension</h1>
<input
value={data}
onChange={(e) => setData(e.target.value)}
className="border p-2 w-full mt-2"
/>
<button onClick={handleSave} className="bg-blue-500 text-white p-2 mt-2">
Save
</button>
</div>
);
}
One of the trickier aspects is communication between different parts of your extension:
// In content script - send message to background
chrome.runtime.sendMessage({ type: 'GET_DATA' }, (response) => {
console.log('Received:', response);
});
// In background script - listen for messages
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'GET_DATA') {
sendResponse({ data: 'Hello from background!' });
}
return true; // Keep the message channel open
});
Building Chrome extensions with React and TypeScript provides a modern development experience while creating powerful browser tools. The component-based approach makes it easy to build complex UIs, and TypeScript ensures your code is robust and maintainable.
In my next post, I'll cover how to publish your extension to the Chrome Web Store and handle the review process.
Get the latest articles, tutorials, and updates delivered straight to your inbox. No spam, unsubscribe at any time.