# suppressHydrationWarning

> What suppressHydrationWarning does in React, why it only works one level deep, when it is safe, and why you cannot turn hydration errors off in Next.js.

Source: https://hydration.jscrate.dev/docs/guides/suppresshydrationwarning
Last updated: 2026-09-18

`suppressHydrationWarning` is a React prop that stops React from reporting a hydration mismatch in one element's own attributes and text. React keeps the server's value and does not patch it. Use it for values that can never match, such as a timestamp or the theme class on `<html>`, and fix everything else.

## What suppressHydrationWarning does

React's docs describe it as a boolean that, when `true`, makes React "not warn you about mismatches in the attributes and the content of that element. It only works one level deep, and is intended to be used as an escape hatch. Don't overuse it." ([react.dev](https://react.dev/reference/react-dom/components/common))

In practice:

- **It covers the element's own attributes and its direct text.** Nothing inside its child elements.
- **React keeps the server value.** The [hydrateRoot docs](https://react.dev/reference/react-dom/client/hydrateRoot) say React "will not attempt to patch mismatched text content". The user sees the server's value until the next render changes it.
- **It does not cover structure.** If the server and client render different elements, the prop cannot hide it.

```tsx title="components/current-date.tsx"
"use client";

export function CurrentDate() {
  // The server's date and the browser's date can differ around midnight.
  return (
    <time suppressHydrationWarning>{new Date().toLocaleDateString()}</time>
  );
}
```

## When is it safe to use?

It is safe when the difference is expected, harmless, and fixed by the next render:

- **A timestamp or a live clock** whose first value does not matter, on the element that shows it.
- **`<html>` or `<body>` attributes a script sets before hydration,** such as the theme class written by next-themes or a similar inline script.

It is not safe as a way to hide a bug. On a price formatted in the wrong locale, it leaves the wrong price on the page with no error. Prefer the fixes in [the causes guides](https://hydration.jscrate.dev/docs/causes): pass the server's value as a prop, or render the value after hydration with [two-pass rendering](https://hydration.jscrate.dev/docs/guides/useeffect-two-pass-rendering).

## Why is suppressHydrationWarning not working?

When you add the prop and the error stays, it is one of these:

1. **It is on a parent, and the difference is in a child.** It only works one level deep.
2. **It is on a component, not an HTML element.** `<RelativeTime suppressHydrationWarning />` does nothing unless the component passes the prop to an element.
3. **The difference is structural.** An element exists on one side only, or is a different element. React re-renders the tree regardless.
4. **The error is about invalid nesting.** "In HTML, `<div>` cannot be a descendant of `<p>`" comes from the browser rewriting the HTML, which no prop can hide.
5. **It is on the wrong element.** next-themes changes `<html>`, so the prop belongs on `<html>`, not on `<body>`.

The first case is the most common:

```tsx title="components/clock.tsx"
"use client";

export function Clock() {
  return (
    // Does nothing: the text is inside the <span>, one level down.
    <div suppressHydrationWarning>
      <span>{new Date().toLocaleTimeString()}</span>
    </div>
  );
}
```

```tsx title="components/clock.tsx"
"use client";

export function Clock() {
  return (
    <div>
      {/* Works: the prop is on the element that holds the text. */}
      <span suppressHydrationWarning>{new Date().toLocaleTimeString()}</span>
    </div>
  );
}
```

## suppressHydrationWarning: Next.js root layout

The usual place for it in Next.js is `<html>` in the root layout, because theme libraries set a class or `style` there before React hydrates. shadcn/ui's [dark mode guide](https://ui.shadcn.com/docs/dark-mode/next) and next-themes both tell you to add it:

```tsx title="app/layout.tsx"
import type { ReactNode } from "react";
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
```

Because it works one level deep, it covers only the attributes of `<html>` itself. A theme toggle that renders a different icon for the current theme still needs its own fix; see [theme hydration errors](https://hydration.jscrate.dev/docs/causes/theme).

## suppressHydrationWarning: React Router root

In React Router's framework mode, `<html>` is rendered by the `Layout` export of `app/root.tsx`. The `Layout` in [React Router's docs](https://reactrouter.com/api/framework-conventions/root.tsx) does not include the prop. Add it only when a script changes `<html>` before hydration, for example to set the theme:

```tsx title="app/root.tsx"
import type { ReactNode } from "react";
import { Links, Meta, Scripts, ScrollRestoration } from "react-router";

export function Layout({ children }: { children: ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <meta charSet="utf-8" />
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <Scripts />
        <ScrollRestoration />
      </body>
    </html>
  );
}
```

## Can you ignore, disable or hide a hydration error in Next.js?

No. Neither React nor Next.js has a setting that turns hydration errors off for a whole app, and [Next.js's hydration error page](https://nextjs.org/docs/messages/react-hydration-error) offers three fixes: `useEffect`, disabling SSR for a component, and `suppressHydrationWarning` on the element.

There is a reason for that. The message is a symptom: by the time it appears, React 19 has already thrown the server HTML away and rendered the tree again on the client. Hiding the log does not stop the re-render, the lost state or the layout shift. And for attributes, React 19 production builds already stay silent while the wrong value stays on the page.

What you can do instead:

- **Fix the cause.** Each cause has a local fix; [the React hydration error guide](https://hydration.jscrate.dev/docs/guides/react-hydration-error) maps each message to one.
- **Render the part on the client only** with a [client-only component](https://hydration.jscrate.dev/docs/guides/client-only-component) or `next/dynamic` with `ssr: false`.
- **Use `suppressHydrationWarning`** on the one element whose value cannot match.
- **Ignore extension noise in tests,** not in the app: a clean browser profile has no extensions, and hydration-proof has [ignore rules](https://hydration.jscrate.dev/docs/ignoring) for attributes you cannot control.

In a custom React setup, the `onRecoverableError` option of `hydrateRoot` decides how recovered errors are logged. It changes the log, not what React does.

## hydration-proof vs suppressHydrationWarning

They answer different questions. `suppressHydrationWarning` hides a difference from React's warnings. hydration-proof finds differences, including the hidden ones, and tells you what each suppression hides.

|                             | `suppressHydrationWarning`                                         | hydration-proof                                                       |
| --------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
| What it does                | Stops React reporting one element's attribute and text differences | Loads every route and compares the server HTML with the client render |
| Scope                       | One element, one level deep                                        | Every element on every tested page                                    |
| The page                    | Keeps the server's value                                           | Unchanged: nothing is added to your app                               |
| Hidden differences          | Invisible from then on                                             | Listed as [HP6001](https://hydration.jscrate.dev/docs/issues/hp6001), for information              |
| Structural differences      | Not hidden                                                         | [HP6002](https://hydration.jscrate.dev/docs/issues/hp6002): the prop cannot hide this              |
| A prop with nothing to hide | Not reported                                                       | [HP6003](https://hydration.jscrate.dev/docs/issues/hp6003): remove it before it hides a future bug |

The ESLint rule [`audit-suppress-hydration-warning`](https://hydration.jscrate.dev/docs/rules/audit-suppress-hydration-warning) catches the misplaced ones while you type: the prop on an element with child elements, on an element with only static content, or on a component. It accepts `<html>` and `<body>` by default, and it checks Server Components too, because the root layout is one.

## Related

- [Intentional differences and how hydration-proof lists them](https://hydration.jscrate.dev/docs/causes/suppressed)
- [Next-themes and dark mode hydration errors](https://hydration.jscrate.dev/docs/causes/theme)
- [useEffect and two-pass rendering](https://hydration.jscrate.dev/docs/guides/useeffect-two-pass-rendering)
- [Ignoring findings in hydration-proof](https://hydration.jscrate.dev/docs/ignoring)
- [React hydration errors: messages and causes](https://hydration.jscrate.dev/docs/guides/react-hydration-error)
