How to Fix: Error: A tree hydrated but some attributes of the server rendered HTML didn’t match the client properties.

6 min read

Next.js Hydration Error: “A tree hydrated but some attributes of the server rendered HTML didn’t match the client properties”

This error means your server-rendered HTML and the client-rendered React tree are not identical at hydration time. In the reported reproduction, the mismatch is triggered by browser-side changes to the DOM before React hydrates, which makes Next.js warn that some attributes no longer match what it rendered on the server.

If you want to inspect the original report, see the reproduction repository.

Understanding the Root Cause

Hydration is the process where React attaches event listeners and internal state to HTML already rendered by the server. For hydration to succeed cleanly, the HTML generated on the server must match what React expects to render on the client.

This specific warning appears when something modifies attributes in the DOM between these two moments:

  1. Next.js sends HTML from the server.
  2. The browser loads the page.
  3. Some external agent changes the markup or attributes.
  4. React hydrates and sees that the DOM no longer matches.

In Chrome, this can happen because of browser extensions, built-in browser features, translation tools, password managers, accessibility tools, auto-fill, or other scripts that inject or rewrite attributes before hydration completes. Even when your application code is correct, those external mutations can still trigger the warning.

Typical examples of hydration mismatches include:

  • Rendering values like Date.now() or Math.random() during render.
  • Reading window, localStorage, or browser-only state on the first render.
  • Conditional markup that differs between server and client.
  • Third-party tools injecting attributes such as data markers, accessibility labels, or autofill metadata.

In this issue, the key detail is that opening a new Chrome tab and navigating can involve browser-level behavior that changes attributes before React hydration, so the warning is not always caused by a logic bug in your React component tree.

Step-by-Step Solution

The fix depends on whether the mismatch comes from your code or from external DOM mutation. Start by isolating the source.

1. Verify whether Chrome extensions or browser features are causing the mismatch

Test the app in a clean environment first:

  1. Open the page in Incognito mode with extensions disabled.
  2. Try another browser such as Firefox or Safari.
  3. Disable password managers, translation extensions, accessibility overlays, and DOM-modifying extensions.

If the warning disappears, your app is likely fine and the mismatch is caused by external mutation before hydration.

2. Make sure your initial render is deterministic

Do not render unstable values directly in server components or in the first client render.

// Bad: different output between server and client possible
export default function Page() {
  return <p>{Date.now()}</p>
}
// Better: render stable fallback, then update on client
'use client'

import { useEffect, useState } from 'react'

export default function Page() {
  const [time, setTime] = useState('')

  useEffect(() => {
    setTime(String(Date.now()))
  }, [])

  return <p>{time || 'Loading...'}</p>
}

3. Guard browser-only APIs

If your markup depends on browser APIs, move that logic into useEffect so it only runs after hydration.

// Bad
export default function Page() {
  const theme = localStorage.getItem('theme')
  return <div>Theme: {theme}</div>
}
// Good
'use client'

import { useEffect, useState } from 'react'

export default function Page() {
  const [theme, setTheme] = useState('default')

  useEffect(() => {
    const value = localStorage.getItem('theme')
    if (value) setTheme(value)
  }, [])

  return <div>Theme: {theme}</div>
}

4. Use suppressHydrationWarning only for known harmless mismatches

If an attribute or text value is expected to differ and cannot reasonably be synchronized, you can suppress the warning for that specific node. This should be a last resort, not the default fix.

export default function Page() {
  return <span suppressHydrationWarning>{new Date().toLocaleTimeString()}</span>
}

Use this carefully. It hides the warning but does not solve real rendering bugs.

5. Isolate client-only UI with dynamic import if needed

For components that depend entirely on browser behavior, render them only on the client.

import dynamic from 'next/dynamic'

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

export default function Page() {
  return <ClientOnlyWidget />
}

This avoids server/client mismatch by skipping SSR for that component.

6. Check the actual mismatched element in DevTools

Inspect the warning closely. React often points to the affected subtree. Compare:

  • The HTML from View Page Source or server output
  • The live DOM in Elements

If you see extra attributes injected by tools you did not write, that confirms an external source.

7. Keep dependencies updated

Hydration warnings can improve across React and Next.js releases. Update to the latest stable versions and retest.

npm install next@latest react@latest react-dom@latest

8. Practical resolution for this issue

For the issue described, the most practical resolution is:

  1. Confirm the warning in a clean browser profile.
  2. If it only happens in normal Chrome usage, identify the browser feature or extension mutating the DOM.
  3. If your own component renders non-deterministic attributes or text, move that logic into useEffect or a client-only component.
  4. Use suppressHydrationWarning only for intentionally different content such as timestamps.

Common Edge Cases

Browser extensions adding attributes

Extensions frequently inject data-* attributes, inline helpers, grammar markers, or form annotations. These changes can trigger hydration warnings even when your code is valid.

Dark mode or theme initialization

If the server renders one theme and the client immediately switches to another based on local storage or system preference, attributes like class on html or body may mismatch.

'use client'

import { useEffect } from 'react'

export default function ThemeInit() {
  useEffect(() => {
    const theme = localStorage.getItem('theme')
    if (theme) document.documentElement.className = theme
  }, [])

  return null
}

Use a synchronized theme strategy to avoid flashes and mismatches.

Locale-sensitive formatting

Dates, currencies, and numbers may render differently on the server and client if locales or time zones differ.

// Risky if server and client locale/timezone differ
new Date().toLocaleString()

Pre-format values on the server or format them only after mount.

Random IDs

Generating IDs with Math.random() during render can break hydration. Prefer React-safe patterns or deterministic IDs.

Conditional rendering based on window size

If you render mobile markup on the client and desktop markup on the server, the trees will differ. Use CSS for responsive layout when possible, or defer browser-width logic until after mount.

FAQ

Is this always a bug in my Next.js app?

No. It can be caused by your code, but it can also be caused by external DOM mutation from browser extensions, translation tools, password managers, or auto-fill features. Always test in a clean browser profile first.

Should I ignore hydration warnings if the page seems to work?

No. Some warnings are harmless, but others indicate real UI inconsistencies that can cause broken interactivity or unexpected re-renders. You should identify whether the mismatch is intentional, external, or a real bug.

When should I use suppressHydrationWarning?

Only when a small piece of content is expected to differ between server and client and that difference is acceptable, such as a live timestamp. Do not use it to hide broader rendering problems across an entire component tree.

The core fix is simple: keep the first render deterministic, move browser-only logic to the client, and verify whether Chrome or an extension is mutating the DOM before hydration. Once the server HTML and client tree are aligned, the warning disappears.

Leave a Reply

Your email address will not be published. Required fields are marked *