CodingCode ReviewIntermediate30 minSaves 30 minutes

React SSR Theme Provider with System Preference & Hydration Safety

For React engineers building SSR applications, this solution provides a robust theme provider that handles system preferences, cookie persistence, and prevents hydration flashes, ensuring a smooth user experience from the first render.

Implement a reliable SSR-compatible React theme provider. This solution detects user system preferences, persists theme choices to cookies, and prevents the "flash of unstyled content" (FOUC) during hydration. It ensures a consistent UI experience across server and client renders.

READY-TO-USE PROMPT

Copy Prompt

prompt.txt
Role:
As an experienced Frontend Engineer with deep expertise in React and Server-Side Rendering (SSR) frameworks, your focus is on building performant, accessible, and type-safe UI components.

Context:
A critical requirement for our new React application, built with an SSR framework, is a theme provider that offers a seamless user experience. This provider must intelligently detect the user's system-level dark/light mode preference, persist their explicit theme choice to a cookie, and crucially, prevent any visual "flash of unstyled content" (FOUC) or hydration mismatches on the initial page load. The solution needs to be solid, maintainable, and adhere to modern React and TypeScript best practices.

Task:
Develop a complete, production-ready, SSR-safe React theme provider. Your output should include all necessary components, hooks, tests, and documentation required for integration into an existing SSR application.

Constraints:
1.  **Language:** All code must be written in TypeScript (TSX).
2.  **System Preference:** The provider must automatically detect the user's `prefers-color-scheme` media query for initial theme determination.
3.  **Persistence:** User-selected themes must be persisted to a browser cookie. This cookie should be readable on both the server and client to prevent hydration issues.
4.  **Hydration Safety:** Implement mechanisms to entirely prevent "flash of unstyled content" (FOUC) and hydration errors when the theme is applied.
5.  **API:** Provide a custom React hook (e.g., `useTheme`) for consuming the current theme and a function to update it.
6.  **Default Theme:** If no system preference or cookie is found, a `{{default_theme}}` (e.g., 'light') should be used.
7.  **Cookie Name:** The cookie key for theme persistence should be configurable via `{{theme_cookie_name}}`.
8.  **Output Structure:**
    *   A file tree outlining the proposed solution.
    *   Full TSX code for the `ThemeProvider` component and `useTheme` hook.
    *   Example usage demonstrating how to wrap the application and consume the theme.
    *   Basic unit tests (e.g., using Jest and React Testing Library) for the provider and hook.
    *   Concise accessibility notes relevant to theme switching.
    *   Brief performance considerations and optimizations.

Output:
Provide the solution structured as described in the constraints, ensuring all code is self-contained and ready for deployment.

Estimated results

DifficultyIntermediate
Setup time30 min
Time saved30 minutes
Best modelsClaude, ChatGPT, Gemini
Best audienceSoftware Development, Web Development

Editor's note

Why this prompt matters

Implementing a theme provider in a React Server-Side Rendered (SSR) application presents specific challenges beyond client-side rendering. Engineers often encounter hydration mismatches or a noticeable flash of unstyled content (FOUC) when dealing with user preferences for light or dark mode. This occurs because the initial server-rendered HTML might not perfectly align with the client-side theme detection, leading to a jarring visual shift as React hydrates the DOM. A common scenario involves detecting the user's prefers-color-scheme on the server, persisting explicit theme choices via cookies, and then ensuring this state is consistently applied across both server and client without visual artifacts.

This workflow addresses those critical synchronization issues, providing a production-ready blueprint for React engineers working on SSR frameworks. It details how to construct a theme provider that respects system preferences, maintains user choices through cookie persistence, and crucially, prevents the visual glitches associated with hydration. The focus is on a solid, maintainable, and type-safe solution, adhering to modern React and TypeScript practices.

By following this approach, you can deliver a smooth, consistent user experience from the initial page load, avoiding the common pitfalls of theme management in complex SSR environments. It’s about building a reliable foundation that enhances accessibility and perceived performance, ensuring your application’s UI remains stable and predictable across all user interactions and rendering phases.

Anatomy

Prompt engineering breakdown

Role

The prompt clearly defines the persona as an "experienced Frontend Engineer with deep expertise in React and Server-Side Rendering (SSR) frameworks," focusing on "performant, accessible, and type-safe UI components." This sets expectations for the quality and technical depth of the response.

Context

It establishes the scenario: a new React SSR application requiring a theme provider that handles system preferences, cookie persistence, and critically, avoids FOUC and hydration mismatches. This provides the necessary background for the task.

Goal

The objective is explicit: "Develop a complete, production-ready, SSR-safe React theme provider," including "all necessary components, hooks, tests, and documentation." This leaves no ambiguity about the expected deliverable.

Constraints

A detailed list ensures the solution meets specific technical and structural requirements: TypeScript, system preference detection, cookie persistence (server/client), hydration safety, custom hook API, configurable default theme and cookie name, and a precise output structure (file tree, TSX, example, tests, accessibility, performance notes).

Output format

The prompt explicitly requires a structured output encompassing a file tree, full TSX code for the provider and hook, example usage, unit tests, accessibility notes, and performance considerations. This guides the model to produce a comprehensive and well-organized response.

Why this structure works

The use of role priming immediately sets the appropriate technical tone and expertise level for the response. Explicit constraints, particularly regarding TypeScript, cookie handling, and hydration safety, ensure the solution addresses the core challenges of SSR theme management. Finally, the structured output mandate guarantees a comprehensive and immediately usable set of assets, including code, tests, and documentation.

Pick your version

Prompt variations

BeginnerWorks with any model

For developers new to React theme management or when building client-side-only applications where server-side rendering complexities are not a concern. Ideal for learning basic context API usage.

prompt.txt
As a React developer, create a simple theme provider. This provider should allow users to switch between 'light' and 'dark' themes. It needs to store the user's preference in `localStorage` so it persists across sessions. Include a `ThemeProvider` component and a `useTheme` hook. The `useTheme` hook should return the current theme and a function to update it. If no preference is found, default to `{{default_theme}}`. Provide the TSX code for the provider and hook, along with a basic example of how to use them in a simple client-side React app. Focus on clarity and ease of understanding for someone new to theme implementation.
ProfessionalBest with claude

When building production-grade React applications with SSR, where hydration safety, system preference detection, and robust cookie persistence are non-negotiable requirements.

prompt.txt
Role: As an expert React and SSR engineer, design and implement a production-ready theme provider. Context: The provider must manage user themes across SSR and client-side, prioritizing system `prefers-color-scheme`, persisting user choices to a secure cookie, and eliminating FOUC/hydration mismatches. Task: Deliver a complete TypeScript solution. Constraints: Use TSX. Implement `prefers-color-scheme` detection. Persist theme to a cookie ({{theme_cookie_name}}) readable by server/client. Guarantee zero FOUC or hydration errors. Provide a `useTheme` hook for consuming and updating the theme. Default to `{{default_theme}}` if no preference. Output: Include a file tree, full TSX code (provider, hook, example usage), Jest/RTL unit tests, accessibility notes, and performance considerations. Ensure the solution is fully self-contained and adheres to modern best practices.
Short VersionBest with chatgpt

When you need a concise prompt for a React SSR theme provider and are confident the model understands the underlying technical requirements without extensive detail.

prompt.txt
Generate a complete, SSR-safe React theme provider in TypeScript. It must detect `prefers-color-scheme`, persist user theme choices to a cookie named `{{theme_cookie_name}}` (readable server/client), and prevent hydration flash. Provide a `useTheme` hook. Default to `{{default_theme}}` if no preference is found. Include the file structure, full TSX code, usage example, basic tests, accessibility notes, and performance tips for integration into an SSR framework.
EnterpriseBest with gemini

For large-scale projects requiring comprehensive solutions that consider compliance, security, scalability, and maintainability, often involving multiple teams or a formal review process.

prompt.txt
Role: As a Principal Frontend Architect, develop a highly resilient and compliant SSR-safe React theme provider. Context: This provider is for a critical enterprise application, necessitating strict adherence to accessibility standards, data privacy (cookie handling), and ensuring no degradation of user experience or SEO due to hydration issues. Scalability and maintainability for long-term support are paramount. Task: Provide a comprehensive, auditable TypeScript solution. Constraints: Must use TSX. Implement `prefers-color-scheme` with `{{default_theme}}` fallback. Securely persist theme to a `{{theme_cookie_name}}` cookie, server/client accessible. Absolutely prevent FOUC and hydration errors. Provide a `useTheme` hook. Include detailed documentation, robust unit and integration tests, comprehensive accessibility notes (WCAG 2.1), performance optimizations (e.g., critical CSS), and considerations for internationalization. Outline potential risks and mitigation strategies.

What you'll get

Expected output

```typescript // src/theme/theme.types.ts export type Theme = 'light' | 'dark'; export type ThemeProviderProps = { children: React.ReactNode; defaultTheme?: Theme; themeCookieName?: string; };

// src/theme/theme.context.ts import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; import type { Theme, ThemeProviderProps } from './theme.types'; import Cookies from 'js-cookie';

const ThemeContext = createContext<{ theme: Theme; setTheme: (newTheme: Theme) => void } | undefined>(undefined);

export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children, defaultTheme = 'light', themeCookieName = 'app-theme', }) => { const [theme, setThemeState] = useState<Theme>(() => { try { const cookieTheme = Cookies.get(themeCookieName); if (cookieTheme === 'light' || cookieTheme === 'dark') { return cookieTheme; } } catch (e) { console.error('Failed to read theme cookie:', e); }

if (typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } return defaultTheme; });

const setTheme = useCallback((newTheme: Theme) => { setThemeState(newTheme); try { Cookies.set(themeCookieName, newTheme, { expires: 365, path: '/' }); } catch (e) { console.error('Failed to set theme cookie:', e); } }, [themeCookieName]);

// Hydration safety: Ensure initial render matches server-side useEffect(() => { const root = document.documentElement; root.style.setProperty('--initial-theme-color', theme === 'dark' ? '#1a202c' : '#ffffff'); // Example CSS variable root.setAttribute('data-theme', theme); }, [theme]);

return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); };

export const useTheme = () => { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; };

// src/theme/index.ts export * from './theme.context'; export * from './theme.types';

// Example Usage (App.tsx) // import { ThemeProvider } from './theme'; // function App() { return (<ThemeProvider><YourAppContent /></ThemeProvider>); }

// Example Usage (Component.tsx) // import { useTheme } from './theme'; // function MyComponent() { const { theme, setTheme } = useTheme(); return (<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Toggle Theme</button>); }

// Tests (theme.test.tsx) // import { render, screen, fireEvent } from '@testing-library/react'; // import { ThemeProvider } from './theme'; // ... tests for initial theme, cookie setting, hook usage ...

// Accessibility: Ensure sufficient contrast ratios for text and UI elements in both themes. // Performance: Minimize re-renders by memoizing theme-related calculations if necessary. ```

Under the hood

Why this prompt works

This prompt is effective due to its structured approach and specific technical requirements. The clear role definition, "Act as an experienced Frontend Engineer," immediately sets the expectation for a high-quality, production-ready output, aligning the model's persona with the target audience's needs.

The detailed 'Context' section provides a realistic problem statement, explicitly mentioning critical issues like "flash of unstyled content" (FOUC) and hydration mismatches. This grounds the task, ensuring the model understands the practical implications and prioritizes solutions for these common SSR challenges.

The 'Constraints' are the most critical element. By enumerating specific technical demands—TypeScript, system preference detection, cookie persistence, hydration safety, and a custom API hook—the prompt guides the model toward a robust, complete solution. The explicit requirement for an 'Output Structure' is particularly effective. It acts as a comprehensive checklist, forcing the model to generate not just code, but also a file tree, example usage, unit tests, accessibility notes, and performance considerations. This ensures a holistic, actionable deliverable, mirroring the components expected in a real-world engineering task and preventing generic or incomplete responses. This level of detail minimizes ambiguity and maximizes the utility of the generated solution for a React engineer.

Model fit

Best AI models for this prompt

Claude

Claude excels at handling complex code generation tasks, particularly where detailed contextual understanding is required. It can manage intricate requirements well, though specific SSR edge cases might necessitate some refinement in the generated output. See the full Claude hub for deeper guidance.

ChatGPT

ChatGPT is effective for generating common React patterns and boilerplate code. It provides a strong foundation for test cases. Users might need to explicitly reinforce strict TypeScript typing to ensure the highest level of type safety. See the full ChatGPT hub for deeper guidance.

Gemini

Gemini is capable of producing coherent code structures that integrate multiple requirements, such as system preference detection and cookie persistence. It generally offers a balanced solution, effectively addressing various technical constraints. See the full Gemini hub for deeper guidance.

When to use

  • When building a public-facing React application using an SSR framework where consistent theming from the first paint is crucial.
  • For applications requiring user preference persistence across sessions without client-side theme flashes.
  • In scenarios where accessibility and performance, specifically regarding initial load and layout shifts, are high priorities.
  • When integrating with design systems that depend on CSS variables or classes applied at the document root.
  • For complex dashboards or portals where user experience demands immediate theme application without visual jarring.

When not to use

  • For purely client-side React applications where SSR benefits are not needed or desired.
  • In internal tools or prototypes where a brief hydration flash is acceptable and development speed is prioritized over pixel-perfect initial rendering.
  • When the application does not require theme persistence across sessions or explicit user theme selection.
  • If the application's styling approach does not rely on global CSS classes or variables for theming.

Get more from it

Pro tips

  • 1

    Inject a small script at the top of your `_document.tsx` or equivalent; this prevents a flash of unstyled content by setting the theme class before React hydrates.

  • 2

    Ensure your server-side rendering logic correctly reads the theme cookie; this avoids hydration mismatches between server and client markup.

  • 3

    Thoroughly test for hydration errors in development mode; this catches discrepancies between server-rendered HTML and client-side React output.

  • 4

    Implement an accessible theme toggle button, providing clear visual and semantic feedback to users regarding their current theme status.

  • 5

    Consider the cookie's `SameSite` attribute for security and cross-site request prevention, balancing it with necessary client-side access for updates.

  • 6

    Verify media query listeners are correctly cleaned up in the `useEffect` hook; this prevents memory leaks in long-running applications.

Don't ship this

Common mistakes

  • Failing to read the theme cookie on the server side, resulting in the server rendering the default theme.

    Fix — Access the `req.headers.cookie` in your SSR framework's data fetching layer to pass the correct initial theme to the component tree.

  • Applying theme classes or styles only after client-side JavaScript loads, causing a noticeable flash of unstyled content (FOUC).

    Fix — Ensure the server pre-renders the `<html>` element with the correct theme class, or inject a blocking script early in `_document.tsx`.

  • Not providing a robust fallback theme if `prefers-color-scheme` is unavailable and no cookie exists.

    Fix — Always define a `default_theme` in your provider's configuration to guarantee a consistent initial state.

  • Ignoring `document.documentElement` for theme application, leading to inconsistent styling across the page.

    Fix — Always apply the theme class to `document.documentElement` to ensure global CSS variable scope and consistent styling.

  • Not handling user overrides correctly, where system preference might clash with an explicitly chosen theme.

    Fix — Prioritize the user's explicit cookie choice over system preference; only fall back to system preference if no cookie is present.

People also ask

Frequently asked questions

Q.How can I extend this provider to support more than just 'light' and 'dark' themes?

You can extend the Theme type to include additional strings like 'sepia' or 'blue'. Update the setTheme logic to accept these new values, and ensure your CSS variables or classes are defined for each theme, switching based on the data-theme attribute on <html>.

Q.Will this approach impact my application's Lighthouse performance scores, specifically for Largest Contentful Paint (LCP)?

Minimal impact on LCP, as the theme is determined server-side or by an early-loading script, preventing layout shifts. The small cookie read is negligible. In fact, by preventing FOUC, it can improve perceived performance and Cumulative Layout Shift (CLS).

Q.Is this theme provider compatible with popular CSS-in-JS libraries like Styled Components or Emotion?

Yes, generally. This provider primarily manages a data-theme attribute on the <html> element or a class. Most CSS-in-JS libraries can consume global CSS variables or context values that react to this root attribute for theme-specific styling.

Q.What happens if a user's browser does not support `prefers-color-scheme`?

If window.matchMedia('(prefers-color-scheme: dark)') is not supported, the provider will fall back to checking for an existing theme cookie. If no cookie is found, it will then default to the {{default_theme}} you have configured, ensuring a stable initial state.

Q.How do I ensure the theme cookie is secure and only accessible when appropriate?

When setting the cookie, ensure you specify Secure if served over HTTPS, and set Path=/ to make it available across the entire site. Consider SameSite=Lax or Strict to mitigate CSRF attacks. Avoid HttpOnly as client-side JavaScript needs to update it.

Version 1.0Last reviewed July 20, 2026
Reviewed by PromptInFlow Editorial Team