Webcomponents based on <table>. Slot out of flow

Viewed 775

I'm try create data-grid with "web component" based on TABLE. I'm use slot in TBODY to append new items. But TR rows rendered out of TBODY. I don't understand this behavior. shadowDom disallow use TABLE and TR elements, possibly the reason is this, but using HTMLElement.appendChild() also doesn't work

<html>
<head>
<script type="module"> 
    class DataGrid extends HTMLElement {
      TEMPLATE_ID = '#data-grid';
      constructor() {
        super();
        this._records = [];
      }
      connectedCallback() {
        let shadow = this.attachShadow({mode: 'open'});
        this._render(shadow);
      }

      _render(shadow){
        let tmpl = document.querySelector(this.TEMPLATE_ID);
        shadow.appendChild(tmpl.content.cloneNode(true));
        //this.appendChild(tmpl.content.cloneNode(true)); //
      }
    }

    customElements.define('data-grid', DataGrid);
</script>
</head>
<body>
    <template id="data-grid">
    <table border="1">
      <thead>
        <tr>
          <th>id</th>
          <th>time</th>
          <th>voltage</th>
        <tr>
      </thead>
      <tbody>
        <slot></slot>
      <tbody>
    </table>
    </template>

    <data-grid>
      <!-- need replaced to component
<grid-row time="" voltage=""> 
 -->
      <tr>
        <td>1</td>
        <td>123123123120</td>
        <td>12.0</td>
      </tr>
      <tr>
        <td>2</td>
        <td>123123133324</td>
        <td>12.1</td>
      </tr>
      <tr>
        <td>1</td>
        <td>123123122330</td>
        <td>12.2</td>
      </tr>
    </data-grid>

 </body>
1 Answers

From the <TR> documentation on MDN:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr

Permitted parents

<table> (only if the table has no child <tbody> element, and even then only after any <caption>, <colgroup>, and <thead> elements); otherwise, the parent must be <thead>, <tbody> or <tfoot>

So

<data-grid>
  <tr>

is not valid HTML

move (invalid) lightDOM to a <table> inside <data-grid> shadowDOM

note: attachShadow() both sets and returns this.shadowRoot for free
No need to create your own shadow variable.

psuedo code:

const table = this.shadowRoot.querySelector("TABLE");
this.querySelectorAll("TR").forEach(table.appendChild);

Related