Lightning Web Component for table rows and cells

  • I'm trying to build a LWC that renders a complex table-based UI. It needs to have distinct rows and columns with dynamically-determined colspans - a real table. It's for assigning lodging, and each row will represent a room and each column for which the room can be assigned. It will involve drag/drop etc.

    I was hoping to make each row and each cell a component, so that data and logic could be encapsulated in each of those. However, that doesn't seem to work because LWC includes a tag w/ the component name in the rendered HTML.

    Here's some test code.

    Table component markup:

    <template>
    <p>
        This is our very nice room table!
    </p>
    <table style="border:1px black solid">
        <!--header row goes here -->
        <template for:each={rooms} for:item="room">
            <c-ncilodgeroomtablerow key={room}>
            </c-ncilodgeroomtablerow>
        </template>
    </table>
    </template>
    

    The var rooms is just set to [1,2,3] in the js controller so that it will iterate 3 times.

    Here's the row component markup, just hard-coded w/ static content for now:

    <template>
    <tr>
        <td>
            cell one
        </td>
        <td>
            cell two
        </td>
    </tr>
    </template>
    

    This does not render as desired. It ends up with everything in one cell, because it puts c- tags around the tr tags, and I think the tr's need to be immediate children of the table. Here's the rendered markup:

    <table style="border: 1px solid black;">
    <c-ncilodgeroomtablerow>
        <tr>
            <td>cell one</td>
            <td>cell two</td>
        </tr>
    </c-ncilodgeroomtablerow>
    <c-ncilodgeroomtablerow>
        <tr>
            <td>cell one</td>
            <td>cell two</td>
        </tr>
    </c-ncilodgeroomtablerow>
    <c-ncilodgeroomtablerow>
        <tr>
            <td>cell one</td>
            <td>cell two</td>
        </tr>
    </c-ncilodgeroomtablerow>
    </table>
    

    I also tried putting the trs in the table component markup, inside the iterator, and then changing the row component to just include the td tags and not the tr's. That didn't work either - again because of the c- tags inside the tr's.

    Is there any way to make something like this work w/ LWCs? Or do I need to look into making a css-based table layout? Open to general advice.

    this is exactly the problem even I have. :(

  • tsalb

    tsalb Correct answer

    2 years ago

    Building on the answer provided already by @sfdcfox, this following seems to be working for me and allows me to componentize the entire row (much easier to emit events this way).

    parent.html

    <table class="slds-table slds-table_bordered slds-border_left slds-border_right">
      <thead>
        <tr class="slds-line-height_reset">
          <th class="" scope="col">
            <div class="slds-truncate" title="Name">Name</div>
          </th>
          <th class="" scope="col">
            <div class="slds-truncate" title="Some Custom Column">Some Custom Column</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <template for:each={iterableDataSet} for:item="row">
          <c-child-row row={row}>
          </c-child-row>
        </template>
      </tbody>
    </table>
    

    childRow.html

    <template>
      <!-- taken straight from SLDS -->
      <th data-label="Name" scope="row">
        <div class="slds-truncate" title={row.Name}>{row.Name}</div>
      </th>
      <td data-label="Some Custom Column">
        <div class="slds-truncate">
          <lightning-input
            data-id={row.Id}
            type="number"
            variant="label-hidden"
            name="inputForDataField"
            onchange={handleOnChange}
            value={row.Data_Field__c}>
          </lightning-input>
        </div>
      </td>
      <!-- more tds .... -->
    </template>
    

    And the critical piece on childRow.css

    :host {
      display: table-row;
    }
    

    Finally got a chance to try this, and worked a treat! Thanks @tsalb

    Wouldn't adding display: contents to the row work too? It would skip over the parent element and therefore give the table proper HTML table structure?

    @GusMelendez that works! IMHO the better solution as it keeps the HTML table structure intact, as you said. In my case it also allowed me to render a td or a th conditionally in a childCell component which otherwise would be a hassle

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM

Tags used