# HP1009: Element missing from the server HTML

> HP1009 (missing element): React's client render produces a node the server HTML does not contain, so React re-renders that part. Causes and how to fix it.

Source: https://hydration.jscrate.dev/docs/issues/hp1009
Last updated: 2026-09-18

HP1009 (`missing-element`) means React's first client render produces an
element or text node that the server HTML does not contain. React cannot
hydrate a node the server never sent, so it discards that part of the page and
renders it again. Render client-only nodes after mount, or with a client-only
component.

| | |
| --- | --- |
| Code | `HP1009` |
| Name | `missing-element` |
| Default severity | Error |
| Group | DOM mismatches |
| What it means | The client render produces a node the server HTML does not contain. |

## What HP1009 (`missing-element`) means

A component rendered more in the browser than on the server: a badge, a banner,
a widget that depends on something only the browser knows. The finding points
at the new node and shows it as the client value, with `(absent)` as the server
value.

Scripts are not counted, and neither are `<link>`, `<meta>`, `<style>`,
`<title>` and `<base>` tags added to `<head>` ([HP1014](https://hydration.jscrate.dev/docs/issues/hp1014)
covers the head). A whitespace-only text node is
[HP1015](https://hydration.jscrate.dev/docs/issues/hp1015), and an element a script or extension inserted
before hydration is reported as a change outside React
([HP4001](https://hydration.jscrate.dev/docs/issues/hp4001)).

## The React error it matches

```text
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
[Expected server HTML to contain a matching](https://hydration.jscrate.dev/docs/errors/expected-server-html-to-contain-a-matching).

## Likely causes

- A count or flag read from [browser storage](https://hydration.jscrate.dev/docs/causes/storage) during
  render.
- A `typeof window !== "undefined"` branch or another
  [browser-only API](https://hydration.jscrate.dev/docs/causes/browser-api).
- A section shown only on small screens: a
  [media query](https://hydration.jscrate.dev/docs/causes/media-query).
- A list that is longer on the client because the client fetched it again:
  [different data](https://hydration.jscrate.dev/docs/causes/data).

## How to fix it

- Render client-only nodes after mount (`useEffect`) or with a client-only
  component.

A cart badge that only exists in the browser:

```tsx title="cart-badge.tsx"
"use client";

export function CartBadge() {
  const count =
    typeof window === "undefined"
      ? 0
      : Number(localStorage.getItem("cart-count") ?? 0);

  return (
    <a href="/cart" id="cart">
      Cart
      {count > 0 && <b className="badge">{count}</b>}
    </a>
  );
}
```

Read the count after hydration, so the first client render matches the server:

```tsx title="cart-badge.tsx"
"use client";

import { useEffect, useState } from "react";

export function CartBadge() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(Number(localStorage.getItem("cart-count") ?? 0));
  }, []);

  return (
    <a href="/cart" id="cart">
      Cart
      {count > 0 && <b className="badge">{count}</b>}
    </a>
  );
}
```

For a whole component that cannot render on the server, see
[client-only components](https://hydration.jscrate.dev/docs/guides/client-only-component) and
[next/dynamic with `ssr: false`](https://hydration.jscrate.dev/docs/guides/next-dynamic-ssr-false).

## Prevent it with ESLint

[`no-storage-in-initial-render`](https://hydration.jscrate.dev/docs/rules/no-storage-in-initial-render),
[`no-window-render-branch`](https://hydration.jscrate.dev/docs/rules/no-window-render-branch) and
[`no-match-media-in-render`](https://hydration.jscrate.dev/docs/rules/no-match-media-in-render) report the
reads that make a component render more in the browser.

## Example

```text
  ✖ /shop 1.2s  1 error
    HP1009 Element missing from the server HTML  (localstorage / sessionstorage read during render, 85%)
      #cart > b  in CartBadge
      server: (absent)
      client: "<b class=\"badge\">2</b>"
      components/cart-badge.tsx:12:21
      → Storage is only available in the browser. Render a neutral value first and read storage in useEffect.
```

## Related

- [HP1008: element only in the server HTML](https://hydration.jscrate.dev/docs/issues/hp1008)
- [HP1007: a different element](https://hydration.jscrate.dev/docs/issues/hp1007)
- [HP1010: React re-rendered a branch](https://hydration.jscrate.dev/docs/issues/hp1010)
- [localStorage and sessionStorage during render](https://hydration.jscrate.dev/docs/causes/storage)
