Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In HTML, <tr> cannot be a child of <table>. This will cause a hydration error. #74189

Open
RakibulBh opened this issue Dec 20, 2024 · 2 comments
Labels
bug Issue was opened via the bug report template.

Comments

@RakibulBh
Copy link

Link to the code that reproduces this issue

https://github.com/RakibulBh/mydeen-waitlist

To Reproduce

Container for the table

<section className="h-screen bg-white px-64 flex flex-col justify-center py-12 space-y-16">
        <h1 className="text-center text-6xl font-bold">
          Why{" "}
          <strong className="text-transparent bg-clip-text bg-gradient-to-br from-[#e54ed0] to-[#ffe4f2]">
            MyDeen
          </strong>{" "}
          and not other apps?
        </h1>
        <FeatureTable />
      </section> 

Tabel component

import React from "react";

const FeatureTable = () => {
  return (
    <table>
      <tr>
        <th>Company</th>
        <th>Contact</th>
        <th>Country</th>
      </tr>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germany</td>
      </tr>
      <tr>
        <td>Centro comercial Moctezuma</td>
        <td>Francisco Chang</td>
        <td>Mexico</td>
      </tr>
    </table>
  );
};

export default FeatureTable;

Current vs. Expected behavior

Table is meant to be rendered with no hydration errors, but hydration error appears after having rendered the table, the table code was taken from W3Schools and HTML is valid. Error mentions that tr cannot be inside a table tag.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.2.0: Fri Dec  6 18:51:28 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T8112
  Available memory (MB): 8192
  Available CPU cores: 8
Binaries:
  Node: 23.4.0
  npm: 11.0.0
  Yarn: N/A
  pnpm: 9.15.0
Relevant Packages:
  next: 14.2.3 // An outdated version detected (latest is 15.1.2), upgrade is highly recommended!
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.3.3
Next.js Config:
  output: N/A
 ⚠ An outdated version detected (latest is 15.1.2), upgrade is highly recommended!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

Which area(s) are affected? (Select all that apply)

Not sure

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

No response

@RakibulBh RakibulBh added the bug Issue was opened via the bug report template. label Dec 20, 2024
@evheniydan
Copy link

Try using <thead> and <tbody> tags and wrap them around tr. This should be a valid HTML.

@icyJoseph
Copy link
Contributor

icyJoseph commented Dec 22, 2024

This is unfortunately a know developer issue, which often comes from this MDN pages section: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics#adding_headers_with_th_elements

This has nothing to do with React, nor Next.js.

If your server sends:

 <table>
   <tr>
     <th>a</th>
     <th>b</th>
     <th>b</th>
   </tr>
   <tr>
 </table>

Before JS runs, the browser, will change it to:

<table>
  <tbody>
    <tr>
      <th>a</th>
      <th>b</th>
      <th>b</th>
    </tr>
    <tr></tr>
  </tbody>
</table>

You can even disable JavaScript, and the tbody is injected there by the browser.

Then React runs hydration, expecting no tbody element, and that leads to an error.

This is specially confusing because, programatically, you can create the first structure with JavaScript on the browser.

Don't believe me? Go to codepen by writing pen.new on your browser address bar, paste the first HTML structure, and see what gets rendered instead, a tbody out of nowhere, no React, no Next.js:

Screenshot 2024-12-22 at 10 57 27

So yeah, that's what's up. There's a similar situation with nested p's as well.

Server sends:

<p class="outer">
    <p class="inner">hello</p>
</p>

Browser renders:

<p class="outer"> </p>
<p class="inner">hello</p>
<p></p>

But programatically:

const outer = document.createElement('p')
const inner = document.createElement('p')
outer.classList.add("outer")
inner.classList.add("inner")
outer.append(inner)
document.body.append(outer)

Creates this in the browser:

<p class="outer"><p class="inner"></p></p>

Which is often, what pure CSR React would allow you to do, sort of, but as I've shown, these are not valid HTML nesting to begin with, which is why the server string is "patched" by the browser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

3 participants