HP1004 (class-mismatch) means the class attribute in the server HTML
differs from the className React renders on the client. React keeps the
server classes, so the page shows the wrong theme or styles until the element
re-renders. The usual causes are a dark mode check during render and CSS-in-JS
class names generated in a different order.
| Code | HP1004 |
|---|---|
| Name | class-mismatch |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | The class attribute rendered on the server differs from the className React renders on the client. The page keeps the server classes. |
What HP1004 (class-mismatch) means
The element exists on both sides, but the set of class names differs. Classes are compared as a set, so the same names in another order do not count.
React does not patch attributes during hydration. In production, React 19
reports nothing and leaves the server classes in place: a user who prefers dark
mode keeps the light theme. hydration-proof compares every reused
element's classes with the className React renders, so it finds this in
production builds too.
The React error it matches
Only development builds report it:
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up.
Warning: Prop `className` did not match. Server: "theme-light" Client: "theme-dark"The first is React 19, the second React 18. See
Prop className did not match and
attributes didn't match.
Likely causes
- The theme: the server cannot know the color scheme, so
a class chosen with
prefers-color-schemeor a stored preference differs. The package's/dark-modetest page is found this way. - CSS-in-JS class names: the library generates class
names from a counter, and a styled component created on one side only (or
without the library's server setup) shifts it. The
/css-in-jstest page creates one styled component only on the server. - A media query or browser storage read during render.
How to fix it
- Make class names deterministic between server and client.
- For themes, read the preference on the server (for example from a cookie) or
set the class with a pre-hydration script and
suppressHydrationWarningon that element. - For CSS-in-JS, set up the library's server style registry so class names are generated in the same order.
A theme read from the browser during render:
"use client";
export function ThemePreview() {
const dark =
typeof window !== "undefined" &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
return <div className={dark ? "theme-dark" : "theme-light"}>Preview</div>;
}Store the theme in a cookie and read it on the server, so the first render already has the right class (Next.js App Router shown):
import { cookies } from "next/headers";
import type { ReactNode } from "react";
export default async function RootLayout({
children,
}: {
children: ReactNode;
}) {
const theme = (await cookies()).get("theme")?.value ?? "light";
return (
<html lang="en" className={theme}>
<body>{children}</body>
</html>
);
}Without a cookie (the first visit), set the class on <html> with a small
inline script that runs before hydration, and mark <html> with
suppressHydrationWarning. The difference is then listed as
HP6001 (info), not as an error. See the
theme cause for the details, and the
CSS-in-JS cause for the style registry.
Prevent it with ESLint
no-match-media-in-render reports
matchMedia in render code, including the color scheme query, and
no-storage-in-initial-render a
theme read from storage.
When the difference is intentional
A theme class set by a pre-hydration script is the case
suppressHydrationWarning exists for. For a legacy area you cannot fix yet,
add an ignore.issues rule with code: "HP1004", a route, a reason and an
expiry date; see ignoring findings.
Example
✖ /settings 687ms 1 error
HP1004 Class name differs between server and client (theme preference (dark/light mode), 99%)
#theme in ThemePreview
attribute: class
server: "theme-light"
client: "theme-dark"
app/settings/ThemePreview.tsx:9:5
→ The server cannot know the color scheme. Store the theme in a cookie and read it on the server, or set the class with an inline script before hydration and mark that element with suppressHydrationWarning.