Skip to content
tezvyn:

Preventing theme flash in SSR apps

Source: interviewHardHow cards are made

Summary

SSR hydration and theme timing.

Key points

flash comes from server not knowing client preference; fix with a blocking inline script setting the theme before paint.

Watch out for

setting the theme only in a useEffect after hydration.

What's really being asked

The interviewer checks your grasp of the SSR lifecycle: what the server knows, when the client hydrates, and why a late theme application flashes. This is a classic dark-mode bug.

The full answer

Explain the root cause: the server renders HTML without access to the user's localStorage or chosen theme, so it emits a default. The browser paints that default immediately. If your only correction happens in a React useEffect, that runs after hydration, so the user sees a flash from the default theme to the correct one. The robust fix is a tiny synchronous, render-blocking inline script placed early in the document head that reads the persisted preference (or the prefers-color-scheme system setting as fallback) and sets data-theme and color-scheme on the html element before the browser paints. Because it is inline and blocking, the correct theme is in place on first paint, and React hydration then matches it.

The mistakes people make

Setting the theme only inside useEffect or componentDidMount, which is too late and guarantees the flash. Trying to read localStorage on the server, which does not exist there. Using an async or deferred script for the theme, which still allows a paint with the wrong theme.

What usually comes next

How do you avoid a React hydration mismatch warning? Why must the script be synchronous and inline rather than an external file? How do you handle users with no stored preference?

A concrete example

You inject in the head a blocking script: it reads localStorage.theme, falls back to matchMedia prefers-color-scheme dark, and sets document.documentElement.dataset.theme accordingly, before any body content paints. The server output uses CSS variables keyed off data-theme, so when the browser paints, the right colors are already applied and the later React hydration is consistent, eliminating the flash.

Interview question

What makes a render-blocking inline script the correct fix for theme flash in an SSR app?

  • a.It sets the theme attribute before first paint, since the server cannot know the client's stored preferenceCorrect
  • b.It eliminates the need for CSS custom properties
  • c.It allows the server to read localStorage during rendering
  • d.It defers theme application until after hydration completes
Why?

The server has no access to client preferences, so a synchronous inline script must apply the theme before paint; a post-hydration effect runs too late. The other options describe the bug, not the fix.

Just read this? Test yourself on what you have been reading.

Read the original → notanumber.in

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on design-systems — each one lists the topics its interview covers.

See open roles