Search code examples
javascripthtmlweb-componentshadow-domcustom-element

Creating a custom table row


I am trying to create a custom table row but having difficulty getting it to behave properly. I've tried the two below methods and they give bizarre results. I realize that this is very easy to to without custom elements but this is a small example of a much larger project. What can I change to achieve the desired result?

class customTableRow extends HTMLElement {
  constructor(){
    super();
    
    var shadow = this.attachShadow({mode: 'open'});
    
    this.tableRow = document.createElement('tr');
    

    var td = document.createElement('td');
    td.innerText = "RowTitle";
    this.tableRow.appendChild(td);
    
    var td2 = document.createElement('td');
    td2.innerText = "RowContent";
    td2.colSpan = 4;
    this.tableRow.appendChild(td2);

    shadow.appendChild(this.tableRow);
  }
  
}

customElements.define('custom-tr', customTableRow);

//Attempt 2
var newTr = new customTableRow;
document.getElementById('table2Body').appendChild(newTr);
td {
  border: 1px solid black;
}
<span>Attempt 1:</span>
<table>
  
  <thead>
    <tr>
      <th>One</th>
      <th>Two</th>
      <th>Three</th>
      <th>Four</th>
      <th>Five</th>
    </tr>
  </thead>
  
  <tbody>
    <custom-tr />
  </tbody>
  
</table>

<hr>

<span>Attempt 2:</span>
<table id="table2">

  <thead>
    <tr>
      <th>One</th>
      <th>Two</th>
      <th>Three</th>
      <th>Four</th>
      <th>Five</th>
    </tr>
  </thead>
  
  <tbody id="table2Body">
<!--     It should append here -->
  </tbody>
  
</table>

<hr>

<span>This is how I want it to look:</span>
<table id="table2">

  <thead>
    <tr>
      <th>One</th>
      <th>Two</th>
      <th>Three</th>
      <th>Four</th>
      <th>Five</th>
    </tr>
  </thead>
  
  <tbody>
    <tr>
      <td>Row Title</td>
      <td colspan="4">Row Content</td>
  </tbody>
  
</table>


Solution

  • A <table> element and its subcomponents <tbody>, <tr> require a very specific syntax. For example, only <tr> elements are authorized as children of <tbody>.

    Therefore you cannot define a element and insert it in <tbody> or <table>. If you do that it will be moved outside of the <table> at parsing. Hence the display of your first example (look the code in the Dev Tools).

    Instead you should define a customized tag instead like in this answer to a similar question.

    Or you should redefine a complete custom table structure with <custom-table>, <custom-tbody>... like in this other answer.

    Also, you should use closing tag <custom-tr></custom-tr>, and insert your CSS rule in the Shadow DOM if you want it to by applied inside it.