How to fix Warning: Prop `style` did not match in React
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>;
}- Move browser-dependent logic into useEffect
- Disable SSR for specific components using dynamic imports
- Configure styled-components for proper SSR
- Use suppressHydrationWarning as an escape hatch
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 heresetStyles({width: window.innerWidth > 768 ? '100%' : '50%'});}, []);if (!mounted) return null; // Or return a loading placeholderreturn <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
- 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
- Dynamic styles based on viewport dimensions (window.innerWidth, window.innerHeight) that can't be determined on the server
- Conditional rendering based on client-only state like user preferences, localStorage, or cookies not available during SSR
- Empty string values in style objects handled differently between server and client environments
- Browser extensions like ColorZilla injecting attributes into the DOM that don't exist in server-rendered HTML
- 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"
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:
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.
In Next.js, you can disable server-side rendering for components that must run client-only:
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.
If using styled-components, ensure you have the correct setup in your Next.js _document.tsx file:
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.
For specific elements where you know the mismatch is harmless and unavoidable, you can suppress the warning:
<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.
Audit your component props and state to ensure they produce identical output on both server and client:
// 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.
Browser extensions can inject attributes into your DOM that don't exist in the server HTML. Test in incognito mode:
# Test your app in incognito/private mode
# If the warning disappears, a browser extension is the culpritCommon 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.
Check if the libraries you're using have known hydration issues:
# 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 optionsFor 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
- ๐React Official Documentation
- ๐Next.js: Text content does not match server-rendered HTML(Official Docs)
- ๐
- ๐
- ๐
- ๐React Documentation: hydrateRoot(Official Docs)