HP1007 (element-mismatch) means the server rendered one element and React
rendered a different one in the same place, such as a <ul> on the server and a
<select> in the browser. React cannot reuse the server's element, so it
discards that part of the page and renders it again. Render the same element
type on both sides.
| Code | HP1007 |
|---|---|
| Name | element-mismatch |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | The server rendered one element and the client rendered a different one in the same place. |
What HP1007 (element-mismatch) means
hydration-proof compares the DOM right before and inside the hydration commit,
and every node keeps its identity, so it sees exactly which element React
replaced and with what. The finding shows the two tags, for example
server: "<ul>" and client: "<select>", on the element's position in the
page.
A tag change is structural: React throws the server HTML away up to the nearest Suspense boundary, which is slower and resets state in that part of the page. When React re-rendered a branch around the element, the finding's evidence names that branch.
When invalid HTML is the reason the elements differ (the browser moved a
<div> out of a <p>), the difference is reported as
HP3001 instead, with this one folded into it.
The React error it matches
Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client.
Warning: Expected server HTML to contain a matching <div> in <div>The first is React 19, the second the React 18 development warning. See the server rendered HTML didn't match the client and Expected server HTML to contain a matching.
Likely causes
- A layout chosen with
matchMediaor the window size during render: a media query. - A branch on
typeof window, the user agent or another browser-only API, such as a link on one side and a<span>on the other. - A flag from browser storage or data the client fetched again: different data.
How to fix it
- Render the same element type on server and client; branch on data that both sides share.
A menu that picks its element from the screen size:
"use client";
export function NavMenu() {
const narrow =
typeof window !== "undefined" &&
window.matchMedia("(max-width: 600px)").matches;
return narrow ? (
<select aria-label="Menu">
<option>Docs</option>
</select>
) : (
<ul>
<li>Docs</li>
</ul>
);
}Render both and let CSS show one, so the markup is the same everywhere:
export function NavMenu() {
return (
<>
<select className="nav-narrow" aria-label="Menu">
<option>Docs</option>
</select>
<ul className="nav-wide">
<li>Docs</li>
</ul>
</>
);
}When the choice really needs JavaScript, render the server's version first and
switch after hydration, or use useSyncExternalStore with a
getServerSnapshot that returns the server's value.
Prevent it with ESLint
no-match-media-in-render,
no-window-render-branch and
no-client-only-initial-state
report the browser reads that pick a different element.
Example
✖ /docs 1.3s 1 error
HP1007 Different element rendered on server and client (screen size or media query read during render, 84%)
#nav > select in NavMenu
server: "<ul>"
client: "<select>"
components/nav-menu.tsx:9:5
→ Use CSS media queries for layout differences, or read matchMedia / window size after mount.