1

When building tables in Lit, sometimes I need to generate different parts of a table in different parts of the code. But when I put everything together, the table does not look the same as if it were declared all in one place.

See this playground for an example of the same table that's assembled two different ways. Is there any way I can make the "two halves" table look the same as the first, while still creating the elements in separate html`` blocks?

I tried creating a table in two different ways (see playground), I expected it to be the same resulting table in both instances. What actually happened is that they looked different, and I want to know why/how to correct this.

1 Answers1

0

Lit does not do string concatenation and each html tag function results in a cached Template element which can be efficiently rendered. This means that each of your html tags get implicitly closed by the browser's HTML parser.

E.g.: html`<table>...` is parsed by the browser into: html`<table>...</table>`. From lit.dev documentation on "Well-formed HTML": https://lit.dev/docs/templates/expressions/#well-formed-html

Lit templates must be well-formed HTML. The templates are parsed by the browser's built-in HTML parser before any values are interpolated. Follow these rules for well-formed templates:

Templates should not contain unclosed elements—they will be closed by the HTML parser.

Therefore instead of the following structure:

// Does not work correctly - do not copy this. For demonstration purposes.
const start = html`<table>`;
const content = html`content`;
const end = html`</table>`;

const result = [start, content, end];
return html`${result}`;

// This would render as: <table></table>content<table></table>

Consider the following structure instead where each html tag function is well formed HTML:

const tableFrame = (content) => html`<table>${content}</table>`;
const content = html`content`;

// Pass the content template result into the table frame.
return tableFrame(content);

The following is your code from the playground example restructured in this way:

<script type="module">
import {LitElement, html, css} from "https://cdn.jsdelivr.net/gh/lit/dist@2/core/lit-core.min.js";

class TableExample extends LitElement {
  static styles = css`table, th, td { border: 1px solid black; }`;
  
  generateTables() {
      const tables = [];
      const tableRow1 = html`
        <tr>
          <td rowspan=2>0</td>
          <td>1</td>
        </tr>`;
      const tableRow2 = html`
        </tr>
          <td>2</td>
        </tr>`;

      const table1 = html`
          <table>
              <tr>
                  <td rowspan=2>0</td>
                  <td>1</td>
              </tr>
              </tr>
                  <td>2</td>
              </tr>
          </table>
      `;
      const tableFrame = (content) => html`<table>${content}</table>`;
      
      // Full table
      tables.push(table1);
      tables.push(html`<br />`);
      
      // Use tableFrame with custom content.
      tables.push(tableFrame(html`<tr><td>Custom Content</td></tr>`));
      tables.push(html`<br />`);
      
      // Use tableFrame with the two rows defined earlier.
      tables.push(tableFrame([tableRow1, tableRow2]));

      return tables;
  }

  render() {
    return this.generateTables();
  }
}
customElements.define('table-example', TableExample)
</script>

<table-example></table-example>

As an additional reference the documentation on Templates: https://lit.dev/docs/templates/expressions/#templates

YouCodeThings
  • 590
  • 3
  • 13