Performance Tips for Firefox New Tab Extensions: Sub-100ms Load Times

Published: (May 3, 2026 at 08:02 PM EDT)
2 min read
Source: Dev.to

Source: Dev.to

Baseline: What Makes a New Tab Feel Fast?

The new‑tab page replaces Firefox’s built‑in page, which is basically instant. Users will notice if yours takes more than 200 ms. Aim for:

  • First paint:
:root { --bg: #fff; --text: #1a1a1a; }
body { margin: 0; background: var(--bg); color: var(--text);
       font-family: system-ui; }
.container { max-width: 800px; margin: 0 auto; padding: 2rem; }
/* Only above‑the‑fold styles here */

Use defer for Scripts

<script src="your-script.js" defer></script>

With defer, the HTML renders before JavaScript runs, so the user sees something immediately.

Apply Theme Before DOM

A flash of the wrong theme is jarring:

<script>
  // Runs immediately, before any rendering
  (function () {
    const theme = localStorage.getItem('theme') || 'auto';
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    const effective = theme === 'auto' ? (prefersDark ? 'dark' : 'light') : theme;
    document.documentElement.setAttribute('data-theme', effective);
  })();
</script>

Yes, this is a tiny synchronous script—but it prevents FOUC.

Load Cached Data First

Don’t wait for an API call before rendering:

async function init() {
  // 1. Apply settings from sync storage (fast, local)
  const prefs = await browser.storage.sync.get(DEFAULTS);
  applyPreferences(prefs);

  // 2. Show cached weather immediately (no network needed)
  const { weatherCache } = await browser.storage.local.get('weatherCache');
  if (weatherCache) {
    displayWeather(weatherCache.data);
  } else {
    showWeatherSkeleton();
  }

  // 3. Fetch fresh data in background
  fetchWeatherAndUpdate(prefs.location);

  // 4. Render clocks (pure JS, no async needed)
  initClocks(prefs.worldClocks);
}

Minimize Storage Reads

Batch storage reads into one call:

// BAD: multiple awaits, multiple IPC calls
const { theme } = await browser.storage.sync.get('theme');
const { location } = await browser.storage.sync.get('location');
const { clocks } = await browser.storage.sync.get('clocks');

// GOOD: one IPC call
const { theme, location, clocks } = await browser.storage.sync.get([
  'theme',
  'location',
  'clocks',
]);

Measuring Performance

// Measure your init time
const t0 = performance.now();
await init();
const t1 = performance.now();
console.log(`Init took ${t1 - t0}ms`);

Use Firefox’s built‑in Performance profiler (F12 → Performance tab) to identify bottlenecks.

Results

With these techniques, Weather & Clock Dashboard achieves:

  • First paint: ~20 ms (cached theme applied synchronously)
  • Cached weather displayed: ~40 ms
  • Clock rendered: ~45 ms
  • Fresh weather visible: ~400 ms (network permitting)

Weather & Clock Dashboard — free Firefox new‑tab with weather, world clocks, and search. MIT licensed.

0 views
Back to Blog

Related posts

Read more »