5 Lessons I Learned Building a Firefox New Tab Extension from Scratch

Published: (May 3, 2026 at 04:51 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

The manifest_version: 3 Transition Is Mostly Smooth, But Watch for Service Worker Gotchas

Firefox now supports Manifest V3, and I decided to go all‑in. Most things just work — declarative content scripts, the new permissions model, cleaner background handling.

But service workers have a critical limitation: they go inactive after 30 seconds. For a new‑tab extension that needs to refresh weather data periodically, this matters.

Solution: fetch weather data on each new‑tab open, not on a persistent background schedule. Cache the result in localStorage and refresh only if the cached data is older than 10 minutes.

async function getWeather() {
  const cached = JSON.parse(localStorage.getItem('weatherCache') || '{}');
  const now = Date.now();

  if (cached.data && (now - cached.timestamp)  fetchWeatherByCoords(pos.coords),
  (err) => {
    // err.code === 1: User denied
    // err.code === 2: Position unavailable  
    // err.code === 3: Timeout
    showManualCityInput(
      err.code === 1
        ? 'Location blocked — enter your city manually'
        : 'Could not detect location'
    );
  },
  { timeout: 5000, maximumAge: 3600000 }
);

Dark Mode Detection in Extensions Is Actually Elegant

Implementing dark/light mode switching is straightforward in extensions. You get prefers-color-scheme support out of the box, plus the option to persist a user preference.

// Auto-detect system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');

// Apply theme
function applyTheme(dark) {
  document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
  localStorage.setItem('theme', dark ? 'dark' : 'light');
}

// Listen for system changes
prefersDark.addEventListener('change', (e) => applyTheme(e.matches));

// On load: check user preference first, then system
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
  applyTheme(savedTheme === 'dark');
} else {
  applyTheme(prefersDark.matches);
}

Users get a “just works” experience (matches their OS setting) with the option to override.


AMO Review Is Actually Quite Fast (and Human)

I expected a multi‑week wait for the Firefox Add‑On (AMO) review process. My experience was surprisingly good:

  • Initial review: ~3 days
  • Reviewer feedback: Specific and actionable (they flagged one eval() call I hadn’t noticed)
  • Follow‑up review: ~1 day

The reviewer pointed out that I was using innerHTML to set a clock time value (unnecessary DOM risk even though the data was internal) and asked me to switch to textContent. Fair point.

Tips to speed up review:

  • Write clean, readable code
  • Minimize permissions to exactly what you need
  • Avoid remote code execution
  • No obfuscation
  • Include source maps if you minify

The Result

After all this, I shipped Weather & Clock Dashboard — it’s open source (MIT), requires no account, and is genuinely useful.

If you’re building a Firefox extension, the developer experience is actually solid. The API documentation has improved dramatically in recent years, and the Mozilla developer community is helpful.

Built with: Pure HTML/CSS/JS · No build step · MIT Licensed

0 views
Back to Blog

Related posts

Read more »

Making my own framework. Any tips?

!Cover image for Making my own framework. Any tips?https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fde...