Back

How to Build Your First Firefox Extension

How to Build Your First Firefox Extension

Building a Firefox extension might seem daunting, but with Manifest V3 and modern WebExtensions APIs, you can create your first working extension in under 10 minutes. This Firefox extension tutorial will walk you through creating a functional MV3 extension that modifies web pages and includes a popup interface.

Key Takeaways

  • Create a working Firefox extension using Manifest V3 in under 10 minutes
  • Build content scripts that safely modify web pages in isolated contexts
  • Implement popup interfaces for user interaction with message passing
  • Follow security best practices with minimal permissions and external scripts

What Are WebExtensions and Why Manifest V3?

WebExtensions are cross-browser compatible add-ons built with standard web technologies—HTML, CSS, and JavaScript. Firefox WebExtensions Manifest V3 represents the current standard for extension development, offering improved security through service workers, better performance with declarative APIs, and stronger cross-browser compatibility.

While Firefox still supports Manifest V2, starting with Manifest V3 ensures your extension remains compatible with future browser updates and aligns with Chrome, Edge, and Safari’s extension architecture. This guide focuses exclusively on MV3 best practices.

Setting Up Your Firefox Extension Project Structure

Let’s build your first Firefox extension step by step. Create a new folder called my-first-extension and add these essential files:

Creating the Manifest V3 Configuration

The manifest.json file is the heart of any extension. Create this file with the following Manifest V3 configuration:

{
  "manifest_version": 3,
  "name": "My Page Enhancer",
  "version": "1.0.0",
  "description": "Enhances web pages with custom styling",
  
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "48": "icon.png"
    }
  },
  
  "content_scripts": [
    {
      "matches": ["*://*.example.com/*"],
      "js": ["content.js"]
    }
  ],
  
  "icons": {
    "48": "icon.png"
  }
}

Note the use of "action" instead of the deprecated "browser_action"—this is a key requirement for Firefox MV3. The manifest follows minimal permissions principles, a core Firefox extension best practice.

Building the Content Script for Page Modification

MV3 content scripts run in an isolated context, protecting your extension code from malicious page scripts. Create content.js:

// content.js - Runs on matching pages
console.log('Extension loaded on:', window.location.href);

// Add a subtle border to all paragraphs
document.querySelectorAll('p').forEach(paragraph => {
  paragraph.style.border = '2px solid #4A90E2';
  paragraph.style.padding = '8px';
  paragraph.style.borderRadius = '4px';
});

// Listen for messages from the popup
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'changeColor') {
    document.body.style.backgroundColor = request.color;
  }
});

This demonstrates how Manifest V3 isolates extension code from the page context, preventing security vulnerabilities common in older extension architectures.

Creating the Firefox Action Popup Interface

The action popup component provides user interaction. Create popup.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    body { 
      width: 300px; 
      padding: 16px;
      font-family: system-ui, -apple-system, sans-serif;
    }
    button { 
      width: 100%; 
      padding: 8px; 
      margin: 4px 0;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <h2>Page Enhancer</h2>
  <button id="blue">Blue Background</button>
  <button id="green">Green Background</button>
  <script src="popup.js"></script>
</body>
</html>

Add the corresponding popup.js to handle user interactions:

// popup.js - Handles popup interactions
document.getElementById('blue').addEventListener('click', () => {
  sendColorChange('#E3F2FD');
});

document.getElementById('green').addEventListener('click', () => {
  sendColorChange('#E8F5E9');
});

async function sendColorChange(color) {
  const [tab] = await browser.tabs.query({
    active: true,
    currentWindow: true
  });
  
  browser.tabs.sendMessage(tab.id, {
    action: 'changeColor',
    color: color
  });
}

Loading and Testing Your JavaScript Firefox Add-on

To test your JavaScript Firefox add-on:

  1. Open Firefox and navigate to about:debugging
  2. Click “This Firefox” in the left sidebar
  3. Click “Load Temporary Add-on”
  4. Select any file from your extension folder

Your extension icon appears in the toolbar. Visit any example.com page to see the content script in action. Click the extension icon to open the popup and test the background color changes.

When you modify files, click “Reload” in about:debugging to apply changes instantly—no browser restart required.

Firefox Extension Best Practices for MV3 Development

Following these Firefox extension best practices ensures your extension passes review and provides a secure user experience:

  • Minimal Permissions: Only request activeTab when you need current tab access, avoiding broad host permissions
  • No Inline JavaScript: MV3’s Content Security Policy blocks inline scripts—always use external .js files
  • Service Workers: For background tasks, use service workers (not covered here but essential for advanced features)
  • Secure Communication: Use browser.runtime.sendMessage() for component communication

Conclusion

You’ve successfully built a working Firefox extension using Manifest V3. The transition from simple content scripts to full-featured extensions follows this same pattern: isolated contexts, message passing, and minimal permissions. Master these fundamentals, and you’ll build secure, performant extensions that users trust.

To expand your skills, explore the Storage API for persisting user preferences, implement background service workers for complex event handling, and review the latest MDN WebExtensions documentation for API updates.

FAQs

Yes, WebExtensions using Manifest V3 are largely compatible across browsers. Minor differences exist in API namespaces where Chrome uses chrome and Firefox uses browser, but Firefox supports both for compatibility.

The manifest.json file specifies match patterns in the content_scripts section. Change the matches array to include other domains or use broader patterns like *://*/* for all sites, though this requires careful security consideration.

Package your extension as a ZIP file, create a developer account on addons.mozilla.org, submit your extension for review, and wait for approval. Firefox typically reviews extensions within 24-48 hours.

Content scripts run in web page contexts and can access and modify DOM elements. Background scripts in MV3 use service workers that handle events and API calls but cannot directly access page content, requiring message passing for communication.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay