Hydration Proof

Search documentation

Find a page or section

Ignore known hydration mismatches

Leave out markup that is meant to differ, and park known findings with a reason.

To ignore known hydration mismatches, add them to the ignore option: skip an element's subtree, never compare an attribute, mask a text pattern, or accept one finding with a reason and an expiry date. Ignored findings stay in the report, marked as ignored with the reason, and do not fail the run.

When to ignore known hydration mismatches

Ignoring is for markup that is meant to differ between the server and the browser: an ad slot, analytics attributes, a third-party chat widget. A difference in your own components is a bug, and the causes pages show how to fix each one.

Prefer the narrowest tool, and write down why. For an app that already has many findings, record a baseline instead: it accepts today's findings in one step and still fails on new ones.

You want toUse
Skip an element in your own markupThe data-hydration-proof-ignore attribute
Skip third-party markup you cannot editignore.selectors
Never compare an attribute, such as data-gtm-*ignore.attributes
Ignore text that differs only in one part, such as a timeignore.textPatterns
Accept one known finding for a whileAn ignore.issues rule with a reason and expires
Accept every current finding while you fix themA baseline
Keep a value that differs on purpose, in the app itselfsuppressHydrationWarning (reported as info)

Mark an element with data-hydration-proof-ignore

The subtree of any element with this attribute is not compared:

ad-slot.tsx
export function AdSlot() {
  // The ad script fills this element before React hydrates.
  return <div id="ad-slot" data-hydration-proof-ignore />;
}

[data-hydration-proof-ignore] is always part of ignore.selectors, so nothing else needs configuring.

Ignore selectors, attributes and text patterns

For markup you cannot edit, list it in the config:

hydration-proof.config.ts
import { defineConfig } from "hydration-proof";
 
export default defineConfig({
  ignore: {
    // Third-party markup that is expected to differ.
    selectors: ["#ad-slot", "[data-chat-widget]"],
    // Attribute names, or patterns.
    attributes: [/^data-gtm-/],
    // "Updated 10:41" and "Updated 10:42" count as equal.
    textPatterns: [/\d{2}:\d{2}/],
  },
});
  • selectors: elements whose subtree is not compared.
  • attributes: attribute names (strings) or patterns (RegExp) that are never compared.
  • textPatterns: a text difference is ignored when both values are equal after removing these patterns.

Ignore one finding with a reason

An ignore.issues rule accepts specific findings. It matches on any combination of code, route (a glob), fingerprint and selector, and every field you give must match. reason is required and is shown in reports:

hydration-proof.config.ts
import { defineConfig } from "hydration-proof";
 
export default defineConfig({
  ignore: {
    issues: [
      {
        code: "HP4001",
        route: "/checkout",
        reason: "The payment iframe rewrites its container. Ticket ACME-431.",
        expires: "2026-12-31",
      },
    ],
  },
});
  • code: an issue code, such as HP1004.
  • route: a route glob, matched against the path and the route pattern.
  • fingerprint: the exact fingerprint of one finding, from report.json.
  • selector: a CSS selector prefix the finding must point at.
  • expires: an ISO date after which the rule stops applying.

A fingerprint stays the same across runs as long as the problem does: the same code, route pattern, element and attribute. It never depends on values that change per request, so a rule written against it keeps matching.

An expired rule fails the run

After its expires date, a rule that still matches a finding fails the run with "Ignore rule "…" expired on 2026-12-31." That way a temporary exception cannot quietly become permanent: fix the finding, or extend the date on purpose.

How suppressHydrationWarning differs from ignoring

suppressHydrationWarning changes your app: React keeps the server's text or attribute on that element and does not report the difference. ignore changes nothing in the app, only what hydration-proof reports.

hydration-proof still sees what suppressHydrationWarning hides, and audits it:

CodeSeverityFinding
HP6001infoA mismatch hidden by suppressHydrationWarning
HP6002errorA structural difference it cannot hide: it only covers the element's own text and attributes
HP6003infosuppressHydrationWarning on an element with nothing to suppress

checks.suppressedWarnings sets how much of this you see: 'info' (the default) lists the differences it hides, 'strict' also flags unused suppression, and 'off' hides both. See when suppressHydrationWarning is safe, and the ESLint rule audit-suppress-hydration-warning to catch misuse in your editor.

Where ignored findings show up

Each report format handles ignored findings its own way:

  • The terminal summary counts them as "Ignored issues".
  • The HTML report hides them until you tick "Show ignored", then shows each one with the rule and the reason.
  • SARIF includes them with an external suppression, so code scanning does not open alerts for them.
  • JUnit lists them, but they never fail a test case. The GitLab Code Quality report leaves them out.

Options

OptionTypeDefaultDescription
selectorsstring[]Elements whose subtree is not compared. [data-hydration-proof-ignore] is always included.
attributes(string | RegExp)[]Attribute names (or patterns) that are never compared.
textPatternsRegExp[]Text differences are ignored when both values are equal after removing these patterns.
issuesIgnoreRule[]Ignore specific findings.
OptionTypeDefaultDescription
codestringIssue code, e.g. HP1004.
routestringRoute glob.
fingerprintstringExact issue fingerprint from a report.
selectorstringCSS selector prefix the issue must point at.
reason*stringWhy this is ignored. Shown in reports.
expiresstringISO date after which the rule stops applying (and CI fails).