Back to docsRecipe

Dark mode strategy

Ship a polished dark theme without the flicker. This recipe covers server-side class injection, system preference detection, and persistent user overrides — all with zero runtime cost.

1. The flicker problem

If you toggle dark mode in JavaScript after the page paints, users see a white flash. The fix is injecting a class on <html> before the first frame. Next.js App Router makes this trivial with a blocking script in the head.

2. Server-side preference read

Read the prefers-color-scheme media query via a cookie or inline script. Store the resolved value in a cookie so middleware can set the class on every server-rendered response. No hydration mismatch, no flash.

3. User toggle persistence

When a user explicitly picks light or dark, write a cookie with SameSite=Lax; Path=/; Max-Age=31536000. Middleware checks this cookie first; falls back to the system preference. The cookie is HttpOnly-optional — reading it client-side for instant toggle is fine.

4. Tailwind integration

Use darkMode: 'class' in your Tailwind config. Every utility prefixed with dark: activates when <html> has the dark class. Combine with CSS custom properties for brand tokens that swap cleanly.

5. Meridian defaults

Meridian ships dark-first. The root layout injects the blocking script; a ThemeProvider context handles the toggle. Colors use violet #8B5CF6 and pink #F472B6 on a #0A0612 base. Everything respects prefers-reduced-motion.

Next step

Read the theme tokens reference for the full color scale and component mapping.