React

Fix: Hydration failed because the initial UI does not match what was rendered on the server

Advertisements

Within a React or Next.js app, if you encounter the error “Hydration failed because the initial UI does not match what was rendered on the server”, there could be a few reasons for it.

Let us look at all the possible reasons and potential fixes for the error.

Potential issues

Incorrect HTML formatting

The most common cause for the error is incorrect HTML formatting in our code.

But why does the browser not tell you that but instead throws the error “Hydration failed because the initial UI does not match what was rendered on the server”? Because the browser tries to fix these on its own and then does a comparison of the HTML it has from what the server sent, it fails to match the two. Thus it throws the generic error.

Some examples of invalid HTML are as follows.

Having a div element inside a paragraph is not allowed.

export const IncorrectComponent = () => {
  return (
    <p>
      <div>Incorrect HTML</div>
    </p>
  )
}
JavaScript

A paragraph inside another paragraph is erroneous too. The same goes for an H1, or a list item too.

export const IncorrectComponent = () => {
  return (
    <p>
      <p>p inside paragraph is invalid</p>
      <h1>H1 inside paragraph is invalid too</h1>
    </p>
  )
}


export const AnotherIncorrectComponent = () => {
  return (
    <ul>
      <p>
        <li>Incorrect HTML</li>
      </p>
    </ul>
  )
}
JavaScript

The Link tag that is provided by Next.js is already rendered as an anchor component. Trying to add another anchor inside it will throw an error too, since an anchor cannot be placed inside another.

export const IncorrectComponent = () => {
  return (
    <Link>
      <a>Link tag already creates an anchor tag, so this errors too</a>
    </Link>
  )
}
JavaScript

<table> must have a <thead> or a <tbody> before adding any table rows (<tr> ).

export const IncorrectComponent = () => {
  return (
    <table>
      tbody is needed inside a table
    </table>
  )
}
JavaScript

Images inside an anchor tag throw an error too.

export const IncorrectComponent = () => {
  return (
    <a>
      <img />
    </a>
  )
}
JavaScript

Locale objects

When working with locale objects, like date or time objects that are being rendered in the component, it could lead to a mismatch in the output of the component. Who doesn’t love timezones, right?

export const IncorrectComponent = () => {
  return (
    {new Date().toLocaleString()}
  )
}
JavaScript

Incorrect CSS formatting

Incorrect CSS formatting can also lead to the error. For example, if you forget to add quotes when specifying background image

.image {
  background-image: url(https://www.wisdomgeek.com)
}
CSS

Extensions

Another possible reason is that an extension might be inserting something in the client page that might lead to this error since the rendered HTML is different than what the server sent.

Accessing the window object

If our component tries to access the window object, that is not going to be available on the server. That can lead to this error. This is pretty common when using a third-party component. Even checks like  typeof window !== 'undefined' can lead to this error.

Sometimes you still need to access some of the properties mentioned above and there is no workaround. For those cases, there are a couple of possible solutions to fix it. Let us take a look at those next.

Potential workaround solutions

Use a useEffect to run only on the client side

We can intentionally render something different on the client side by using a variable that gets updated inside a useEffect hook.

import { useState, useEffect } from 'react'
 
export default function App() {
  const [isClient, setIsClient] = useState(false)
 
  useEffect(() => {
    setIsClient(true);
  }, [])
 
  return (
    <>
      {isClient && <>{/* Window related checks or components can go here */}</>}
      {!isClient && "Pre-rendered content"}
    </>
  )
}
JavaScript

Disable SSR

Another potential solution is to disable prerendering altogether for a component. In Next.js, we can do so using the following:

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('./Component'), { ssr: false })

export default NewComponent = () => {
  return (
    <>
      <DynamicComponent />
    </>
  )
}
JavaScript

Use suppressHydrationWarning

We can suppress the warning altogether by adding the HTML attribute suppressHydrationWarning to the component or element. For example, if we have a custom component that we want to suppress the warning for:

export default Component = () => {
  return (
    <>
      <CustomComponent suppressHydrationWarning={true} />
    </>
  );
}
JavaScript

And those are all the potential solutions for fixing the “Hydration failed because the initial UI does not match what was rendered on the server” error. Let us know in the comments if you are still facing the error.

Saransh Kataria

Born in Delhi, India, Saransh Kataria is the brain behind Wisdom Geek. Currently, Saransh is a software developer at a reputed firm in Austin, and he likes playing with new technologies to explore different possibilities. He holds an engineering degree in Computer Science. He also shares his passion for sharing knowledge as the community lead at Facebook Developer Circle Delhi, NCR which is a developer community in Delhi, India.

Share
Published by
Saransh Kataria

Recent Posts

Remapping keyboard keys to avoid Carpal Tunnel

I am terrible at optimizing my keyboard layout for anything. But off lately, my little…

2 weeks ago

Fixing cookies are blocked for a website with shields down on Brave

I recently switched completely to the Brave browser and have set ad blocking to aggressive…

4 months ago

Generating a QR code using Node.js

I was preparing a slide deck for a hackathon and decided to put in a…

5 months ago

How to clear the global npx cache

I have been using npx a lot lately, especially whenever I want to use a…

6 months ago

Copy/Pasting output from the terminal

Manually copy-pasting the output of a terminal command with a mouse/trackpad feels tedious. It is…

6 months ago

How To Get The Hash of A File In Node.js

While working on a project, I wanted to do an integrity check of a file…

7 months ago
Advertisements