0Pricing
React Academy · Lesson

Persisting Theme and Preventing Flash

Save theme preference to localStorage and inject a blocking script to set the theme before React loads.

Persisting Theme and Preventing Flash is a free React Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Flash of Wrong Theme Problem

When a page loads, React must download, parse, and execute JavaScript before it can read localStorage and apply the correct theme. During this gap, the browser renders using the default styles. If the user prefers dark mode but your default is light, they see a brief white flash before the theme corrects itself.

The Blocking Script Solution

The fix is an inline script placed in the document head that runs synchronously before any other code. This script reads localStorage immediately and sets data-theme on document.documentElement. Because it is a blocking script, the browser applies the attribute before painting any content.

Why Blocking Is Required

Async or deferred scripts run after the HTML is parsed and potentially after the first paint. That defeats the entire purpose. The blocking inline script must have no async or defer attributes and must not be loaded from an external file. The script must be tiny to minimize the performance cost.

The Inline Script Content

The blocking script is minimal: read localStorage.getItem('theme'), check window.matchMedia('(prefers-color-scheme: dark)').matches as a fallback, then call document.documentElement.setAttribute('data-theme', theme). Wrap it in a try-catch in case localStorage is unavailable in private browsing.

Next.js Implementation

In Next.js, use the Script component from next/script with strategy="beforeInteractive" inside _document.js. The beforeInteractive strategy injects the script into the page HTML before any page JavaScript runs, achieving the same blocking behavior in the Next.js build pipeline.

Vite and CRA Implementation

In a Vite or Create React App project, edit index.html directly and place the inline script tag in the head before any other scripts. Since index.html is the entry point for the browser, the script runs before React boots. Keep it concise to stay under 100 bytes.

SSR Solution via Cookie or Header

In a server-rendered app, the server can read the theme from a cookie sent with the request. The server then sets data-theme in the rendered HTML before sending it to the browser. This avoids any client-side flash entirely because the correct theme is in the very first byte of HTML.

The Complete No-Flash Flow

The complete flow is: browser downloads HTML, parser encounters blocking inline script, script reads localStorage and sets data-theme, parser continues, page is painted with correct theme, React hydrates and picks up the same theme from localStorage. The user sees one consistent theme from the start.

Testing Flash Prevention

To verify the fix works, open Chrome DevTools, go to the Network tab, and throttle to Slow 3G. Reload the page. If you see a theme change during load, the flash is not fixed. With the blocking script in place, the initial paint should already show the correct theme even on slow connections.

Hydration Mismatch Risk

If your React initial state defaults to light but the blocking script set dark before hydration, React may warn about a hydration mismatch. Avoid this by initializing React theme state by also reading localStorage during the initial render, ensuring the React-rendered HTML matches the DOM state set by the blocking script.

Flash in Storybook and Test Environments

Storybook and test environments do not load your index.html, so the blocking script never runs. Provide a decorator or test setup that applies a default data-theme attribute in those environments. This prevents confusing visual inconsistencies when developing components in isolation.

Flash Prevention Technique

What type of script must be used in the document head to prevent the flash of wrong theme?

Lesson Recap: Persisting Theme and Preventing Flash

Prevent the flash of wrong theme by injecting a tiny inline blocking script in the document head that reads localStorage and sets data-theme before any paint. In Next.js use strategy="beforeInteractive", in Vite/CRA add it directly to index.html. SSR apps can read a cookie to set the theme server-side.

Frequently asked questions

Is the “Persisting Theme and Preventing Flash” lesson free?

Yes — the full text of “Persisting Theme and Preventing Flash” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.

What will I learn in “Persisting Theme and Preventing Flash”?

Save theme preference to localStorage and inject a blocking script to set the theme before React loads. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Academy?

No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Persisting Theme and Preventing Flash” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Academy lesson?

Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Detecting System Color Scheme
  2. CSS Variables for Theme Switching
  3. React Context for Theme State
  4. Persisting Theme and Preventing Flash
← Back to React Academy