#Hydration Error in Form

92 messages · Page 1 of 1 (latest)

half ravine
#

Hello, in the login form of my site i encounter this error.```text
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

Did not expect server HTML to contain a <div> in <div>.

<Login>
<div>
^^^^^
<div>
^^^^^```
problem being my component/form is pretty basic:

const Login = () => {
  return (
    <div className="">
      <div className="w-full bg-formideo-white">

        <h1 className="text-xl font-bold font-poppins mb-6">
          Connectez-vous
        </h1>
        <form className="">
          <input type="email" placeholder="E-mail" className={inputStyle} />
          <input type="password" placeholder="Mot de passe" className={inputStyle}  />
          <div className="flex flex-col mt-4 items-end">
            <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
            <ButtonComponent
              buttonLabel="Connexion"
              buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
              buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
              type="submit"
            />
          </div>
        </form>
      </div>
    </div>
  );
};

export default Login;```
I've isolated the problem to the 2 inputs, when both are commented, no hydration error happens.
When one or the other are commented there's no hydration error.
when both  are active, there's hydration error.
when placeholders are removed hydration error is still there.
when placeholders are removed and ONE or both of the inputs are changed to text, the error is no longer there.
when inputs are both changed to text, but there's a placeholder, i get a hydration error.
What can be causing this? i\m trying to bugfix but i can't find any logic
fiery robinBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

rancid blaze
#

@half ravine I think the issue lies with your div container with an empty class. I see no reason for using that since you already have one div wrapping both the h1 and form tags. Try to remove the outer div. It should work.

#

You will mostly face such errors when you have repetitive and same html tags as parent and child.

half ravine
#

why should the title H1 be inside the Form?
normally or what i understood is that my pages are to be encapsulated in one <div> .
If i were to create a <FormComponent> it would also be rendered under the <div> by the parent eventually, i fail to understand the logic in why does this div cause that

half ravine
#
const Login = () => {
  return (
    <form className="">
      <h1 className="text-xl font-bold font-poppins mb-6">
        Connectez-vous
      </h1>
      <input type="email" className={inputStyle} />
      <input type="password" className={inputStyle} />
      <div className="flex flex-col mt-4 items-end">
        <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
        <ButtonComponent
          buttonLabel="Connexion"
          buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
          buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
          type="submit"
        />
      </div>
    </form>
  );
};

export default Login;```
like this it works:
but like this:
```tsx
const Login = () => {
  return (
      <h1 className="text-xl font-bold font-poppins mb-6">
        Connectez-vous
      </h1>
    <form className="">
      <input type="email" className={inputStyle} />
      <input type="password" className={inputStyle} />
      <div className="flex flex-col mt-4 items-end">
        <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
        <ButtonComponent
          buttonLabel="Connexion"
          buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
          buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
          type="submit"
        />
      </div>
    </form>
  );
};

export default Login;```it doesn't
does that mean all my forms must use the complete of the page or am i missing something?
rancid blaze
#

No no, in your original code, you had two div tags. You just have to remove the outer tag so the result would be: ```const Login = () => {
return (
<div className="w-full bg-formideo-white">
<h1 className="text-xl font-bold font-poppins mb-6">
Connectez-vous
</h1>
<form className="">
<input type="email" placeholder="E-mail" className={inputStyle} />
<input type="password" placeholder="Mot de passe" className={inputStyle} />
<div className="flex flex-col mt-4 items-end">
<Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
<ButtonComponent
buttonLabel="Connexion"
buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
type="submit"
/>
</div>
</form>
</div>
);
};

export default Login;```

#

Now if that gives you an error as well, means you are wrapping your Login component inside another div tag.

#

Yup it won't make sense to nest h1 and other tags unrelated to form inside form tags so you would usually wrap your form component inside a div tag and nest other tags inside it. I also do that as well.

#

From your original code, you only remove your outermost div and keep the inner div that wraps both your h1 and form tags

half ravine
# rancid blaze Now if that gives you an error as well, means you are wrapping your `Login` comp...

my Login is just a Login page, so it goes like Layout --> login ---> form.
i tried these 2 approachs:

const Login = () => {
  return (
    <form className="">
      <h1 className="text-xl font-bold font-poppins mb-6">
        Connectez-vous
      </h1>
      <input type="email" className={inputStyle} />
      <input type="password" className={inputStyle} />
      <div className="flex flex-col mt-4 items-end">
        <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
        <ButtonComponent
          buttonLabel="Connexion"
          buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
          buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
          type="submit"
        />
      </div>
    </form>
  );
};```
```tsx
    <div>

      <form className="">
        <h1 className="text-xl font-bold font-poppins mb-6">
          Connectez-vous
        </h1>
        <input type="email" className={inputStyle} />
        <input type="password" className={inputStyle} />
        <div className="flex flex-col mt-4 items-end">
          <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
          <ButtonComponent
            buttonLabel="Connexion"
            buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
            buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
            type="submit"
          />
        </div>
      </form>
    </div>```
#

the second approach throws the hydration error.```text
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

Did not expect server HTML to contain a <div> in <div>.

<Login>
<div>
^^^^^```

rancid blaze
#

If that's the case can you show me the snippet from layout?

#

Can only mean that you must be doing <div>{children}</div> in layout. Otherwise there should not be an error.

half ravine
# rancid blaze If that's the case can you show me the snippet from layout?
interface RootLayoutProps {
  children: ReactNode;
}
export default async function RootLayout({ children }: RootLayoutProps) {
  const footerData = await fetchAllProfessions();
  const navigationData = navBarData as NavBarProps;
  return (
    <html lang="fr">
      <body className={`bg-primary ${poppins.variable} ${sofia.variable}`}>
        <HeaderTop
          profession={navigationData.profession}
          display='flex lg:hidden  w-auto sticky top-0 z-50'
        />
        {children}
        <Suspense fallback={<div>Loading....</div>}>
          <FooterComponent
            navigationLinks={footerData}
          />
        </Suspense>
      </body>
    </html>
  );
}``` i didn't create a layout for Login as it did not use a navbar at all so i went straight for the page ...but i think there might be the issue
#

my other layouts have a <main> declaration and i apparently missed it on my login...tsx return ( <div className='m-3 lg:m-8'> <Header interiorWrapperStyle='h-[120dvh] md:h-[120dvh] lg:h-[80dvh] lg:min-h-[800px] lg:rounded-xl lg:bg-gradient-card' exteriorWrapperStyle='h-[120dvh] md:h-[120dvh] lg:h-[80dvh] relative lg:min-h-[800px]' imageDesktopClassname="w-auto absolute bottom-0 right-0 hidden md:h-[20vh] lg:block lg:h-[60vh] xl:h-[70vh] min-h-[350px]" imageMobileClassname="w-auto h-[55dvh] sm:h-[65vh] md:h-[60vh] absolute bottom-0 flex lg:hidden" imageDesktopHeight={852} imageDesktopWidth={883} imageMobileHeight={330} imageMobileWidth={320} srcDesktop={CatalogueFooterData.desktopPicture} srcMobile={CatalogueFooterData.mobilePicture} footerContainerStyle='flex justify-center' > <CatalogueHeaderBody data={catalogueBodyData} /> </Header> <main> {children} </main> </div> );

rancid blaze
#

Is your repo public?

#

If your login page doesn't have a layout, it will take the layout of the nearest layout.tsx file so might have to take a look at there.

#

Also try to restart the server. Helps sometimes.

half ravine
#

but htank you, you insight was indeed the issue

#

as i had my login page not inside <main>

#

ah ok wasn't that, i tried writing <main> inside the page and same problem occured

half ravine
rancid blaze
#

Is the issue fixed by the way?

half ravine
#

nope, i tried this ```tsx
const Login = () => {
return (
<main>
<form className="">
<h1 className="text-xl font-bold font-poppins mb-6">
Connectez-vous
</h1>
<input type="email" className={inputStyle} />
<input type="password" className={inputStyle} />
<div className="flex flex-col mt-4 items-end">
<Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
<ButtonComponent
buttonLabel="Connexion"
buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
type="submit"
/>
</div>
</form>
</main>
);
};

export default Login;```

#

and i get the hydration error

#

is there some kind of logic i'm missing, or some way to inspect my element?

rancid blaze
#

Okay send me the full error message

#

Then i will walk you through with inspecting element...

half ravine
#
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
See more info here: https://nextjs.org/docs/messages/react-hydration-error

Did not expect server HTML to contain a <div> in <main>.


<Login>
  <main>```
#

Root Layout:

// src/app/layout.tsx
import React, { ReactNode } from 'react';
import "./globals.css";
import { poppins, sofia } from "@src/app/fonts";
import { Suspense } from 'react';
import FooterComponent from '@src/app/ui/footer/FooterComponent';
import { fetchAllProfessions } from './lib/api/fetchOperations';
import { navBarData } from "@src/app/utils/localDb/placeholderData";
import { NavBarProps } from '@src/app/ui/header/Navbar';
import HeaderTop from '@src/app/ui/header/HeaderTop';
interface RootLayoutProps {
  children: ReactNode;
}
export default async function RootLayout({ children }: RootLayoutProps) {
  const footerData = await fetchAllProfessions();
  const navigationData = navBarData as NavBarProps;
  return (
    <html lang="fr">
      <body className={`bg-primary ${poppins.variable} ${sofia.variable}`}>
        <HeaderTop
          profession={navigationData.profession}
          display='flex lg:hidden  w-auto sticky top-0 z-50'
        />
        {children}
        <Suspense fallback={<div>Loading....</div>}>
          <FooterComponent
            navigationLinks={footerData}
          />
        </Suspense>
      </body>
    </html>
  );
}
#

/Login

import Image from "next/image";
import Link from "next/link";
import ButtonComponent from "@src/app/components/common/buttons/ButtonComponent";
const inputStyle = "w-full p-2 rounded-lg border border-slate-200 mb-2 font-poppins bg-gray-50";
const Login = () => {
  return (
    <main>
      <form className="">
        <h1 className="text-xl font-bold font-poppins mb-6">
          Connectez-vous
        </h1>
        <input type="email" className={inputStyle} />
        <input type="password" className={inputStyle} />
        <div className="flex flex-col mt-4 items-end">
          <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
          <ButtonComponent
            buttonLabel="Connexion"
            buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
            buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
            type="submit"
          />
        </div>
      </form>
    </main>
  );
};

export default Login;```
#

as soon as my form is encapsulated by anything

#

i get the hydration error

#

even after i gave it a layout like the other pages

rancid blaze
#

What is your nextjs version?

#

Also for now you can remove the main tag, open devtool, and send me a screenshot of the html elements till the form tag like one above

half ravine
#

Next.js (14.2.4)

#

okay

half ravine
#

i also tried with what it says in the doc:
suppressHydrationWarning and it doesn't change anything

rancid blaze
#

Could you remove that className prop from form tag or try giving it some value

#

If nothing works there is one final solution that will work.

half ravine
#
const Login = () => {
  return (
    <div>

      <form className="w-3/4" suppressHydrationWarning={true} >
        <h1 className="text-xl font-bold font-poppins mb-6">
          Connectez-vous
        </h1>
        <input type="email" className={inputStyle} />
        <input type="password" className={inputStyle} />
        <div className="flex flex-col mt-4 items-end">
          <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
          <ButtonComponent
            buttonLabel="Connexion"
            buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
            buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
            type="submit"
          />
        </div>
      </form>
    </div>
  );
};

export default Login;```
#

that's with something inside, gonna remove aswell

#

same issue without className

rancid blaze
#

Okay try this, take all the code inside Login component into a new component LoginForm and use that inside your login page like so <LoginForm />

#

If there is till try error, mark the LoginForm component with use client. And if it still has error then the final solution is the tell nextjs not to pre-render the login form component. So let's try above before we make that change.

half ravine
#

'use client sends error too

#
'use client'
import Link from "next/link";
import ButtonComponent from "@src/app/components/common/buttons/ButtonComponent";
const inputStyle = "w-full p-2 rounded-lg border border-slate-200 mb-2 font-poppins bg-gray-50";
const LoginForm = () => {
    return (<form suppressHydrationWarning={true} >
        <h1 className="text-xl font-bold font-poppins mb-6">
            Connectez-vous
        </h1>
        <input type="email" className={inputStyle} />
        <input type="password" className={inputStyle} />
        <div className="flex flex-col mt-4 items-end">
            <Link className="text-primary-green text-sm font-medium font-poppins" href="/forgot-password">Mot de passe oublié ?</Link>
            <ButtonComponent
                buttonLabel="Connexion"
                buttonStyle="w-full text-white text-sm font-bold font-poppins justify-center"
                buttonContainerStyle=" h-[50px] px-[18px] py-3.5 bg-formideo-custom-gradient rounded-lg mt-6 w-full"
                type="submit"
            />
        </div>
    </form>);
}
export default LoginForm; ```
rancid blaze
half ravine
#

why is all this comming from a <form> ?

#

it is specially if there's a div encapsulating my <form> doesn't make any logical sense

rancid blaze
#

By the way your login page is not marked as use client right?

half ravine
#

no

#

the page not

#

the component yes

rancid blaze
#

Alright have you used nextjs dyamic function?

half ravine
#

nope

rancid blaze
#

Inside you login page import this import dynamic from 'next/dynamic'

#

Next: do this const ComponentA = dynamic(() => import('../components/A')), ComponentA is your component name so should be LoginForm in your case and give the relative path to your login form component

#

const ComponentC = dynamic(() => import('../components/C'), { ssr: false })

#

Add that {ssr: false} option as well

half ravine
#

C would be what?

rancid blaze
#

../components/C replace all this with path to your login form component

half ravine
#

wasn't t that A?

#

i got this: ```tsx
import dynamic from 'next/dynamic'

const Login = () => {
const LoginForm = dynamic(() => import('../ui/login/LoginForm'), {
ssr: false
});
return (
<LoginForm />
);
};

export default Login;

rancid blaze
#

You should do this const LoginForm = dynamic(() => import('../ui/login/LoginForm'), { ssr: false }); outside of your component

#

Now the error should disappear

half ravine
#

So like this?

rancid blaze
#

Yup true.

half ravine
#

it works boss, thank you

#

but i don't really get why we encountered this in the first place

#

i guess for a Login form to disable SSR won't hurt the SEO much?

fiery robinBOT
#
✅ Success!

This question has been marked as answered! If you have any other questions, feel free to create another post

Jump to answer

[Click here](#1275377786390974525 message)

rancid blaze
# half ravine but i don't really get why we encountered this in the first place

I also have no idea haha. From my opinion, it shouldn't be throwing any error. For your information, the reason why it worked because of our final solution is because by loading the component dynamically, we are saying nextjs not to pre-render our login form component on the server by setting the flag: {ssr: false}. Now nextjs don't have to compare the html on the server vs client so no hydration error. By default in nextjs, even if your component is a client component, it will pre-render on the server so we are disabling that feature for your login form.

half ravine
#

should i remove 'use client' from the component and just leave the ssr: false?

rancid blaze
# half ravine i guess for a Login form to disable SSR won't hurt the SEO much?

As for the SEO, in your login form component, you only keep the contents inside form tag there and move your h1 tag up to your login page like so. const Login = () => { return ( <div> <h1>Login</h1> <LoginForm /> </div> ); };. Now your h1 tag always render on the server and only the form is rendered on the client. Plus you can also configure metadata for your login page as well to enhance SEO. That way you can still have better SEO while making your form entirely client component

#

You still need to keep use client directive in your LoginForm component.

#

I believe later on you will make use react hooks for form validations and all? so

half ravine
#

i see, thank you!, one last question should recover pass / connection button be part of the <form> or also outside it?

rancid blaze
#

You can keep that inside the form component as those aren't really necessary for SEO. Feel free to mention me if you have any other nextjs related issues/questions. Happy to help.

half ravine
#

thank you very much!

rancid blaze
#

@half ravine I just found this answer from reddit: Deleting .next folder and starting localhost again will simply fix it. Next time you face the same issue try this and also you can check for the current issue we discussed as well.

half ravine
#

the error came back