How to fix Warning: Prop `style` did not match in React

ReactINTERMEDIATEMEDIUMUpdated Dec 8, 2025ยท 162 views

This hydration warning appears when inline style attributes differ between server-rendered HTML and the initial client render. It commonly occurs in SSR frameworks like Next.js when components use browser APIs, dynamic styling, or CSS-in-JS libraries that generate different output on server versus client.

Quick fix

Fixes Warning: Prop `style` did not match

import { useState, useEffect } from 'react';

export default function Component() {
  const [mounted, setMounted] = useState(false);
  const [styles, setStyles] = useState({});

  useEffect(() => {
    setMounted(true);
    // Safe to use window/document here
    setStyles({
      width: window.innerWidth > 768 ? '100%' : '50%'
    });
  }, []);

  if (!mounted) return null; // Or return a loading placeholder

  return <div style={styles}>Content</div>;
}
  1. Move browser-dependent logic into useEffect
  2. Disable SSR for specific components using dynamic imports
  3. Configure styled-components for proper SSR
  4. Use suppressHydrationWarning as an escape hatch
react โ€” error
import { useState, useEffect } from 'react';
export default function Component() {
const [mounted, setMounted] = useState(false);
const [styles, setStyles] = useState({});
useEffect(() => {
setMounted(true);
// Safe to use window/document here
setStyles({
width: window.innerWidth > 768 ? '100%' : '50%'
});
}, []);
if (!mounted) return null; // Or return a loading placeholder
return <div style={styles}>Content</div>;
}
Warning: Prop `style` did not match

What this error means

This warning is a React hydration error that occurs specifically when the style prop on an element differs between what was pre-rendered on the server (SSR/SSG) and what React generates during the first client-side render (hydration). During hydration, React expects to reuse the existing server-rendered DOM and simply attach event handlers, but when it detects mismatched attributes, it issues this warning. The warning indicates that React found an inline style attribute with different CSS properties or values between the server HTML and client JavaScript. This mismatch prevents React from efficiently hydrating the component and may cause the UI to be "stale" - React won't update the attribute to match the client-side props, instead keeping the server-rendered version. While the warning itself won't break your application, it signals that your server and client are rendering different output, which can lead to unexpected visual bugs, accessibility issues, or SEO problems where the initial HTML doesn't match what users ultimately see.

Typical symptoms

  • Console warning appears: "Warning: Prop `style` did not match. Server: '...' Client: '...'"
  • Components flash or jump on initial page load after hydration completes
  • Inline styles appear differently between initial page load and after JavaScript executes
  • Warning appears specifically when using next/image or other built-in Next.js components
  • Issue occurs only on first page load, not on client-side navigation
  • Warning appears when using CSS-in-JS libraries like styled-components, emotion, or Material-UI
  • Problem manifests in components that depend on window or document objects for styling

Common causes

  1. Style serialization differences between server and browser - React with jsdom adds spaces after colons and trailing semicolons ("text-decoration: none;") while browsers don't ("text-decoration:none")
  2. Using browser APIs (window, document, navigator) directly in render logic that returns different values than server defaults
  3. CSS-in-JS libraries generating different class names or styles on server versus client, especially without proper SSR configuration
  4. Dynamic styles based on viewport dimensions (window.innerWidth, window.innerHeight) that can't be determined on the server
  5. Conditional rendering based on client-only state like user preferences, localStorage, or cookies not available during SSR
  6. Empty string values in style objects handled differently between server and client environments
  7. Browser extensions like ColorZilla injecting attributes into the DOM that don't exist in server-rendered HTML
  8. Third-party libraries (react-virtualized, react-color, Material-UI Fade) that apply dynamic styles during hydration

How to fix "Warning: Prop `style` did not match"

1Move browser-dependent logic into useEffect

The most reliable fix is to defer any browser-specific logic to client-side only using the useEffect hook, which never runs during server rendering:

jsx
import { useState, useEffect } from 'react';

export default function Component() {
  const [mounted, setMounted] = useState(false);
  const [styles, setStyles] = useState({});

  useEffect(() => {
    setMounted(true);
    // Safe to use window/document here
    setStyles({
      width: window.innerWidth > 768 ? '100%' : '50%'
    });
  }, []);

  if (!mounted) return null; // Or return a loading placeholder

  return <div style={styles}>Content</div>;
}

This ensures the server renders a consistent fallback, then the client updates after hydration.

2Disable SSR for specific components using dynamic imports

In Next.js, you can disable server-side rendering for components that must run client-only:

jsx
import dynamic from 'next/dynamic';

const ClientOnlyComponent = dynamic(
  () => import('../components/ClientOnlyComponent'),
  { ssr: false }
);

export default function Page() {
  return (
    <div>
      <ClientOnlyComponent />
    </div>
  );
}

This tells Next.js to skip rendering this component on the server entirely, preventing any hydration mismatches.

3Configure styled-components for proper SSR

If using styled-components, ensure you have the correct setup in your Next.js _document.tsx file:

tsx
import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

This collects and injects server-side styles so they match the client.

4Use suppressHydrationWarning as an escape hatch

For specific elements where you know the mismatch is harmless and unavoidable, you can suppress the warning:

jsx
<div suppressHydrationWarning>
  <time>{new Date().toLocaleString()}</time>
</div>

Important: This only works one level deep and doesn't fix the underlying issue. Use sparingly and only when you've confirmed the mismatch is intentional and won't cause visual bugs.

5Ensure consistent state between server and client

Audit your component props and state to ensure they produce identical output on both server and client:

jsx
// BAD - Will cause mismatch
function BadComponent() {
  const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
  return <div style={{ width: isMobile ? '100%' : '50%' }}>Content</div>;
}

// GOOD - Consistent on server and client
function GoodComponent({ isMobile }) {
  return <div style={{ width: isMobile ? '100%' : '50%' }}>Content</div>;
}

Pass environment-specific values as props from a layout or page component that handles detection properly.

6Check for browser extensions injecting attributes

Browser extensions can inject attributes into your DOM that don't exist in the server HTML. Test in incognito mode:

bash
# Test your app in incognito/private mode
# If the warning disappears, a browser extension is the culprit

Common culprits include ColorZilla, Grammarly, and translation extensions. While you can't control user extensions, you can add suppressHydrationWarning to the affected element or document the known issue.

7Update third-party libraries causing mismatches

Check if the libraries you're using have known hydration issues:

bash
# Update libraries that commonly cause style mismatches
npm update @mui/material react-virtualized react-color

# Check GitHub issues for your specific library + "hydration"
# Many libraries have SSR-specific configuration options

For Material-UI components like Fade, you may need to disable transitions on the server or configure the StylesProvider properly.

Advanced notes

Style serialization differences between JSDOM (used by React SSR) and actual browsers are a known issue tracked in React issue #11807. React purposely matches the style property by string value rather than parsing and normalizing CSS, which is why even semantically identical styles ("margin:0" vs "margin: 0") can trigger warnings.

For production applications, consider implementing a two-pass rendering strategy where the server renders a safe fallback UI, and the client immediately does a second render after hydration with the full dynamic styles. This adds a small performance cost but eliminates all hydration warnings.

In Next.js 13+ with app directory, you can use the "use client" directive to explicitly mark components as client-only, providing a clearer boundary than dynamic imports. This is especially useful for components that heavily depend on browser APIs.

If you're using CSS-in-JS, consider migrating to zero-runtime solutions like vanilla-extract or Linaria that generate static CSS at build time, eliminating server-client style mismatches entirely. Alternatively, newer libraries like Panda CSS and StyleX are designed with SSR hydration in mind from the ground up.

Frequently asked questions

What does "Warning: Prop `style` did not match" mean?
This warning is a React hydration error that occurs specifically when the style prop on an element differs between what was pre-rendered on the server (SSR/SSG) and what React generates during the first client-side render (hydration). During hydration, React expects to reuse the existing server-rendered DOM and simply attach event handlers, but when it detects mismatched attributes, it issues this warning. The warning indicates that React found an inline style attribute with different CSS properties or values between the server HTML and client JavaScript.
How do I fix "Warning: Prop `style` did not match"?
This hydration warning appears when inline style attributes differ between server-rendered HTML and the initial client render. It commonly occurs in SSR frameworks like Next.js when components use browser APIs, dynamic styling, or CSS-in-JS libraries that generate different output on server versus client.
What causes "Warning: Prop `style` did not match"?
Style serialization differences between server and browser - React with jsdom adds spaces after colons and trailing semicolons ("text-decoration: none;") while browsers don't ("text-decoration:none") Using browser APIs (window, document, navigator) directly in render logic that returns different values than server defaults CSS-in-JS libraries generating different class names or styles on server versus client, especially without proper SSR configuration
Is the "Warning: Prop `style` did not match" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading