Frontend Development 14 min read

Guide to Developing Chrome Extensions with Manifest V3

This article explains the fundamentals of Chrome extension development using Manifest V3, covering concepts such as the manifest file, service workers, content scripts, UI pages, and provides step‑by‑step code examples to build a color‑extraction extension.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Guide to Developing Chrome Extensions with Manifest V3

Introduction

Chrome extensions (also called plugins) are software programs built with web technologies (HTML, CSS, JavaScript) that let users customize their browsing experience. This guide introduces the basic concepts, development workflow, and walks through creating a simple background‑color extraction extension based on Manifest V3.

Basic Concepts

Manifest

The manifest.json file is mandatory and must reside in the extension’s root directory. It defines metadata, resources, permissions, and declares which files run in the background or on pages.

Service Worker

The Service Worker handles and listens to browser events (e.g., navigation, bookmark removal, tab close). It can use all Chrome APIs but cannot directly interact with web pages; that requires Content Scripts.

Content Scripts

Content Scripts run in the context of a web page, can read and modify the DOM, and have access to a limited set of Chrome APIs. Other APIs are accessed indirectly via the Service Worker.

Popup and Pages

Extensions may include HTML files such as popups or option pages, which can also access Chrome APIs.

Building a Simple Extension

Below is a minimal "Hello Extensions" example.

Creating manifest.json

{
  "manifest_version": 3,
  "name": "Hello Extensions",
  "description": "Base Level Extension",
  "version": "1.0",
  "action": {
    "default_popup": "hello.html",
    "default_icon": "hello_extensions.png"
  }
}

Place an icon file in the directory and reference it via default_icon .

Creating hello.html

<html>
  <body>
    <h1>Hello Extensions</h1>
  </body>
</html>

Loading the Extension

In Chrome, open chrome://extensions , enable Developer Mode, and click “Load unpacked” to select the extension folder.

After loading, you can pin the extension to the toolbar, open the popup, and see the UI.

Reloading the Extension

Changing the name field in manifest.json (e.g., to "Hello Extensions of the world!") requires clicking the refresh button on the extensions page to apply the change.

Extension Component

Requires Reload?

The manifest

Yes

Service worker

Yes

Content Scripts

Yes (plus the host page)

The popup

No

Options page

No

Other extension HTML pages

No

Console and Error Logs

Add a script tag to the popup HTML:

<script src="popup.js"></script>

In popup.js you can log messages:

console.log("This is a popup!")

Introducing a syntax error (e.g., missing a quote) will surface an error button in the extension UI, allowing you to inspect the problem.

Extension Project Structure

The manifest.json must stay at the root. A typical structure includes the manifest, background script, content scripts, HTML pages, CSS, and icons.

Content Script Details

Content Scripts run in the page context and can access the DOM. Example:

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener("click", () => alert(greeting + button.person_name + "."), false);
  </script>
</html>

Content Scripts can be injected statically via the content_scripts field in the manifest, dynamically when matches are unknown, or programmatically for event‑driven scenarios.

Service Worker

The Service Worker listens for Chrome events (installation, updates, bookmark changes, etc.) and runs only when needed, sleeping after 30 seconds of inactivity.

chrome.runtime.onInstalled.addListener(function(details) {
  console.log("onInstalled event has been triggered with details: ", details);
  if (details.reason == "install") {
    // code for install
  } else if (details.reason == "update") {
    // code for update
  } else if (details.reason == "uninstall") {
    // code for uninstall
  }
});

Listening to Events

chrome.bookmarks.onCreated.addListener(function(id, bookmark) {
  console.log("Bookmark created with title: " + bookmark.title + " and url: " + bookmark.url);
});

Filtering Events

chrome.webNavigation.onCompleted.addListener(() => {
  console.info("The user has loaded my favorite website!");
});

Service Worker ↔ Content Script Communication

The Service Worker can send messages to content scripts using chrome.tabs.sendMessage , while content scripts listen with chrome.runtime.onMessage.addListener .

Color Extraction Extension Example

The following core code implements a panel that shows the background color of any element the user clicks.

Manifest Configuration

{
  "manifest_version": 3,
  "name": "EasyColor",
  "description": "Chrome extension for obtaining color in an easy way",
  "version": "0.0.1",
  "action": { "default_icon": "images/icon-48.png" },
  "icons": { "16": "images/icon-16.png", "32": "images/icon-32.png", "48": "images/icon-48.png", "128": "images/icon-128.png" },
  "background": { "service_worker": "background.js" },
  "content_scripts": [{
    "matches": ["http://*/*", "https://*/*"],
    "css": ["css/styles.css"],
    "js": ["scripts/content.js"],
    "run_at": "document_start"
  }],
  "web_accessible_resources": [{
    "resources": ["/pages/panel.html"],
    "matches": ["http://*/*", "https://*/*"]
  }]
}

Opening the Panel from the Toolbar

chrome.action.onClicked.addListener(function(tab) {
  // open pages
  chrome.tabs.sendMessage(tab.id, { action: "EVENT_PANEL_OPEN" });
});

Content Script: Injecting the Iframe Panel

chrome.runtime.onMessage.addListener((req, sender, sendResp) => {
  const data = req;
  if (data.action === "EVENT_PANEL_OPEN") {
    let easyPanel = document.getElementById(easyPanelId);
    if (easyPanel == null) {
      easyPanel = document.createElement("iframe");
      easyPanel.id = easyPanelId;
      easyPanel.src = chrome.runtime.getURL("../pages/panel.html");
      easyPanel.style.width = "100%";
      easyPanel.style.height = "100%";
      easyPanel.style.borderRadius = "20px";
      easyPanel.style.border = "none";

      const container = document.createElement("div");
      container.id = easyContainerId;
      container.style.width = "200px";
      container.style.height = "250px";
      container.style.position = "fixed";
      container.style.top = "10px";
      container.style.right = "10px";
      container.style.zIndex = "10000";
      container.style.boxShadow = "3px 2px 22px 1px rgba(0, 0, 0, 0.24)";
      container.style.borderRadius = "20px";
      container.appendChild(easyPanel);

      document.body.appendChild(container);
    }

    document.addEventListener("mousemove", handleMouseMove);

    document.addEventListener("click", function(e) {
      e.stopPropagation();
      e.preventDefault();
      return false;
    }, true);
  }
});

Displaying the Selected Color

document.addEventListener("mousedown", function(e) {
  const easyPanel = document.getElementById(easyPanelId);
  if (easyPanel == null) { return; }
  const cpStyle = window.getComputedStyle(e.target);
  easyPanel.contentWindow.postMessage({
    type: "computedStyle",
    data: JSON.stringify({
      color: cpStyle.color,
      backgroundColor: cpStyle.backgroundColor
    })
  }, "*");
});

For full details, see the GitHub repository linked in the article.

Reference Resources

Official Chrome Extension documentation: https://developer.chrome.com/docs/extensions/mv3/

JavaScriptChrome ExtensionWeb Developmentservice-workerManifest V3Content Script
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.