How to Create a Browser Extension
Intro
Have you ever wished you could customize your browsing experience with a unique tool? Creating a browser extension is a fantastic way to do that. We’ll break down the process into easy-to-follow steps.
We’ll create a browser extension that allows users to change the background color of any web page.
Prerequisites:
- Node.js on your computer.
- NPM on your computer.
- Some JavaScript knowledge.
- JSON.
- An understanding of the browser DOM.
Acronym meanings:
- DOM: Document Object Model.
- JSON: JavaScript Object Notation.
- UI: User Interface.
- CSS: Cascading Style Sheet.
- HTML: HyperText Markup Language.
If you want to follow along, I have an example repository used in this article.
Understanding The Basics
Before we dive into the code, let’s understand the core components of a browser extension:
- Manifest File (manifest.json): This file is the heart of your extension. It defines the extension’s name, description, version, permissions, and files used.
- Background Script: This script handles tasks like events, network requests, and storing data.
- Content Script: These scripts run on web pages and interact with the page’s DOM.
- Popup Page: This is the UI that appears when the user clicks on the extension’s icon. It allows users to interact with the extension and its features.
Set Up Your Development Environment
- Install Node.js and npm: Used for managing dependencies and running development tools.
- Create a New Project Directory: This will house all your extension files.
- Initialize a New Project: Use
npm init -yto create a package.json file.
Create The Manifest File manifest.json
The manifest.json file is in the root of the project folder.
This is a basic example of the manifest.json file.
{
"manifest_version": 3,
"name": "My First Extension",
"version": "1.0",
"description": "A simple extension to demonstrate the basics.",
"permissions": [
"activeTab",
"scripting"
],
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["content.css"]
}
],
"action": {
"default_popup": "popup.html"
}
}An important line for this extension is the permissions. The activeTab permission allows us to access the current browser tab. The scripting allows us to inject scripting into the tab. We need these permissions, our example will change the current tab background color.
The matches line defines where the extension runs in the browser, "<all_urls>" means it will run on any page. This is beneficial if you want to create an extension for a specific website or a set of websites. This way it will not interfere with the user’s other websites and can provide a better user experience.
Notice the two files background.js and content.js. Background.js is the browser extension service worker. Service workers handle events and perform tasks in the background. Content.js provides any content interactions within browser pages for the browser extension. Next, we’ll create these files and program them.
Create the Background Script background.js
In the root project folder create the file background.js.
This script performs tasks like setting alarms, making network requests, and storing data.
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed!');
});
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'changeColor') {
console.log('Change color message background received!');
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length > 0) {
for (const tab of tabs) {
console.log("Active tab ID:", tab.id);
console.log("Active tab URL:", tab.url);
chrome.tabs.sendMessage(tab.id, { action: 'changeColor' });
}
} else {
console.log("No active tab found.");
}
});
}
});In this example, log ‘Extension installed!’, to the browser console. After installing the extension this message will appear.
We have a listener for receiving messages from the popup. If the message action is changeColor, send a message to the current tab to change the color. In the content.js we’ll handle the changing of the background color.
Create The Content Script content.js
In the root project folder create the file content.js.
This script can interact with the DOM of web pages.
console.log('Content script injected!');
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'changeColor') {
console.log('Change color message on content.js received!');
document.body.classList.add('blue-background');
}
});In our example, we log ‘Content script injected!’ to the browser console on any page.
Then, we add a listener for messages and if the message is changeColor. If the message is changeColor, add the blue-background class to our page body. We’ll add a blue-background class in our css to override the background-color styles on the body.
Create The Popup Script popup.js
In the root project folder create the file popup.js.
This script can interact with anything in the popup.
document.getElementById('changeColorButton').addEventListener('click', () => {
console.log('Change color button clicked in popup.js!');
chrome.runtime.sendMessage({ action: 'changeColor' });
});In our example we use this to add a click event listener on the changeColorButton element. When it’s clicked send the message with the action of changeColor
Create The Popup Page popup.html
In the root project folder create the file popup.html.
This HTML file will define the UI of your popup.
<!DOCTYPE html>
<html>
<head>
<title>My Extension Popup</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<h1>This is our extension popup.</h1>
<h2>Click the button to trigger our page background color to change.</h2>
<button id="changeColorButton">Make Current Tab Background Blue</button>
<script src="popup.js"></script>
</body>
</html>Notice in the html we load the popup.css file for our popup styles. We have a button with the id changeColorButton to watch for click events. Finally, we load a script popup.js to load a script to send our changeColor message.
Load The Popup Page in The Manifest File manifest.json
To load the popup page without extension add the popup field to manifest.json.
{
"manifest_version": 3,
"name": "My First Extension",
"version": "1.0",
"description": "A simple extension to demonstrate the basics.",
"permissions": [
"activeTab",
"scripting"
],
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["content.css"]
}
],
"action": {
"default_popup": "popup.html"
}
}Create The Content CSS File content.css
In the root directory create the content.css CSS file. These styles get injected in any page that the extension runs on.
body {
background-color: green !important; /* IMPORTANT: Override all page styles with ours. */
}Let’s set the background color to green.
Create The Popup CSS File popup.css
In the root directory create the popup.css CSS file. These styles get loaded into our extension popup. This allows us to change how the popup will look.
body {
min-width: 300px;
padding: 20px;
}
h1 {
margin-top: 0;
}Load The Extension in Chrome
- Go to
chrome://extensions/. - Enable “Developer mode” in the top right corner.
- Click “Load unpacked” and select your extension’s directory.
- You should now see “My First Extension 1.0” listed in your extensions. 1.0 is the version of the extension.
Test The Extension
- There should be a link to the service worker, labeled “service worker”. This link will open a browser console that should say “Extension installed!“. This is from the service worker script background.js.
- When visiting any page in your browser, you should see a green background.
- Note: You’d never want this in a normal situation, we want this for testing. If we would do this for a live extension that would make for a very intrusive user experience.
- You can now go to any page in your browser with your browser console open. In the browser console you will see the console log “Content script injected!“. This is from the content script content.js.
- Note: If you’re no longer developing your extension, you may want to remove it. Then there is no unexpected interference with your daily browsing.
- Note: If you cause an error with your extension, the error may remain unless you click the clear button. It may appear that you have the same error after you make changes.
Make Changes to Extension
- When developing your extension you can make changes to the extension scripts.
- Next, you’ll see a refresh button on the extension page in chrome, this will reload your extension.
More Tips
- Folder Structure: When your extension grows, you should organize your files into folders. I didn’t do that in this blog so it’s easier to find all your files in one place for the demo.
- Example Folder Structure:
- manifest.json
- package.json
- scripts/background.js
- scripts/content.js
- scripts/popup.js
- css/content.css
- css/popup.css
- html/popup.html
- Example Folder Structure:
- Use Chrome Developer Tools: These tools are invaluable for debugging your extension.
- Leverage the Chrome Extension API: This provides a rich features for creating extensions.
- Test: Test your extension on different websites and browsers for compatibility and performance.
- Consider User Experience: Design your extension with a friendly interface and intuitive features.
Conclusion/Key Takeaways
Conclusion summary:
4 takeaways:
- Extension Functionality: You can create extensions that interact with pages.
- Core Components: Manifest file, background scripts, content scripts, and popup pages..
- Development Environment: Node.js and npm are for dependencies and running development tools.
- User Experience: Designing a friendly interface and intuitive features is crucial. Consider the user’s needs and preferences when developing your extension.
Using these steps and the Chrome Extension API, you can create powerful extensions.
References
Example repositories
About the author

Written by Nicholas Diesslin Pizza acrobat 🍕, typographer, gardener, bicyclist, juggler, senior developer, web designer, all around whittler of the web.
Follow Nick on Twitter!