"Extra attributes from the server" means React 18 found DOM attributes that the first browser render did not produce. Check the attribute names. A theme script or browser extension may have added them before hydration; your server may not have sent them at all.
The error
React 18 names the extra attributes:
Warning: Extra attributes from the server: class,style
Warning: Extra attributes from the server: style
Warning: Extra attributes from the server: cz-shortcut-listen
Warning: Extra attributes from the server: data-new-gr-c-s-check-loaded,data-gr-ext-installedThe component stack points to the element, often <body> or <html>.
There is no matching minified production code for this warning.
React 19 includes these differences in its broader attribute warning:
"A tree hydrated but some attributes… didn't match",
for example - cz-shortcut-listen="true".
What extra attributes from the server means
"Extra" means the attribute exists in the DOM but not in React's rendered props. React warns and may leave the DOM attribute in place.
The wording can mislead: the attribute may have come from a script or extension after the server response arrived.
Common causes
| Attribute | Added by | What to do |
|---|---|---|
class, style on <html> | next-themes or your own theme script, before hydration | Add suppressHydrationWarning to <html>. See theme |
cz-shortcut-listen on <body> | The ColorZilla extension | Nothing in your code. See extensions |
data-new-gr-c-s-check-loaded, data-gr-ext-installed | Grammarly | Nothing in your code |
Other data-* or style | A/B testing, analytics or chat scripts | Load them after hydration. See third-party scripts |
| Attributes on many elements | A CDN or proxy rewriting HTML | Turn the rewriting off. See CDNs |
See the React issue for discussion of extension-added markup.
How to fix it
-
Identify the attribute using the table above.
-
Try a clean browser profile. If the warning disappears, check your extensions rather than changing app code.
-
For a theme script, mark
<html>as expected to differ:app/layout.tsx import { ThemeProvider } from "next-themes"; import type { ReactNode } from "react"; export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="en" suppressHydrationWarning> <body> <ThemeProvider attribute="class">{children}</ThemeProvider> </body> </html> ); }The prop covers
<html>itself, not the rest of the page. -
For a confirmed extension attribute on
<body>, you may suppress its development warning. Be aware that this hides other<body>attribute differences too. See suppression limits. -
For your own scripts, stop them from changing React-owned markup before it hydrates.
Find every instance
hydration-proof reports a server-only attribute as HP1005. If a script or extension added it before hydration, the report may show HP4001 or HP4002:
npx hydration-proof testThe test browser has no extensions. To exclude a confirmed attribute added by a script or simulated extension, list it in the config:
import { defineConfig } from "hydration-proof";
export default defineConfig({
ignore: {
attributes: ["cz-shortcut-listen", /^data-gr-/],
},
});audit-suppress-hydration-warning
checks suppression placement. See ignoring findings for
test-only exceptions.