Search code examples
javascripthtmlhtml-tableradix-uihtml-tbody

<tbody> cannot appear as a child of <div> and <div> cannot appear as a child of <table>


Please take a look at the schematic structure of my table. I removed all unnecessary stuff for ease of reading. As you can see, there is a header and there is a body. Only the body is wrapped in ScrollArea (https://www.radix-ui.com/primitives/docs/components/scroll-area), since I want the user to be able to scroll only the body and not the entire table

<table>
 <thead>
  <tr>
    <th>Name</th>
    <th>Surname</th>
    <th>City</th>
  </tr>
 </thead>
 <ScrollArea.Root>
  <ScrollArea.Viewport>
   {data.map((person) => (
     <tbody>
      <tr>
       <td>{person.name}</td>
       <td>{person.surname}</td>
       <td>{person.city}</td>
      </tr>
     </tbody>
  ))}
  </ScrollArea.Viewport>
  <ScrollArea.Scrollbar/>
 </ScrollArea.Root>
</table>

And so, when I go to the page with this table, I receive two warnings in the console:

Warning: validateDOMNesting(...): div cant appear as a child of table.

Warning: validateDOMNesting(...): tbody cannot appear as a child of div.

If I remove ScrollArea from the table, then the warnings disappear. But ScrollArea is very important to me for moving through long tables.

Tell me how can I get rid of these warnings?


Solution

  • I want the user to be able to scroll only the body and not the entire table

    It can be done with simple CSS as well using position: sticky:

    .wrap {
      height: 80vh;
      overflow-y: scroll;
    }
    
    table {
      position: relative;
      width: 100%;
    }
    thead {
      position: sticky;
      top: 0px;
      
      background-color: pink;
      height: 50px;
    }
    td {
      height: 200px;
      text-align: center;
    }
    
    tr:nth-child(2n) {
      background-color: #eee;
    }
    <p>a table with sticky header</p>
    <div class=wrap>
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Surname</th>
          <th>City</th>
        </tr>
      </thead>
      <tbody>
       <!-- {data.map((person) => ( -->
        <tr><td>name1</td><td>surname1</td><td>city1</td></tr>
        <tr><td>name2</td><td>surname2</td><td>city2</td></tr>
        <tr><td>name3</td><td>surname3</td><td>city3</td></tr>
        <tr><td>name4</td><td>surname4</td><td>city4</td></tr>
        <tr><td>name5</td><td>surname5</td><td>city5</td></tr>
        <tr><td>name6</td><td>surname6</td><td>city6</td></tr>
       <!-- ))} -->
      </tbody>
    </table>
    <div>