[SalesForce] LWC Custom Tree grid issue

I am trying to create a custom Tree Grid component in that based on my business use case I'm in need to create every row as a component, and every column as a component. Below is the structure of my component

table container component

<template>
   <table>
    <thead>
    </thead>
    <tbody>
     <template for:each={datas} for:item="d">
            <c-child key={d.Id} data={d}></c-child>
       </template>
    </tbody>
  </table>

</template>

Child component

<template>
  <td>{data.Name}</td>
  <td>{data.age}</td>
  <td>{data.num}</td>
  <td>{data.Email}</td>
          <template for:each={data.childrens} for:item="d">
                <c-child key={d.Id} data={d}></c-child>
           </template>
</template>

Child.css

:host {
  display: table-row;
}

Here My Question is when I try to build a row component recursively for the tree structure . Since My row component doesn't contain <tr> I cannot able to render recursively because every custom element(LWC component) includes a tag with the component name in HTML Lightning Web Component for table rows and cellsbased on this link every row component behaves like a row when applying display: table-row;

So My nested tree structure looks like when I try to build the row component recursively, So my host component behaves like single tr

<c-row>
   <td></td>
   <td></td>
   <c-row>
   <c-row>
</c-row>

Here is a Playground link that I described my issue with a simple example.

UPDATE :

Below is the screenshot of UI I am trying to build

Example Tree Grid

Best Answer

When I want to rebuild/extend some of the functionality for LWC I usually get styling from SLDS. You can check markup here for tree-grid.

Salesforce flattens data and uses aria-expanded, aria-level for styling. I would suggest the same. Here is the script to flatten data. I also updated playground with simple styling for Id

UPDATE: Created separate playground to not override changes.

UPDATE Added expand/hide.

Here is sample row markup with some code.

// rendered.js
let data = [
    { Name:'st1', Id:1, age:'2', num:'342222222', Email:'v@gmail.com' },
    { Name:'st1', age:'2', Id:2, num:'342222222', Email:'v@gmail.com', children:[
        { Name:'st1child', Id:6, age:'2', num:'342222222', Email:'v@gmail.com' },
        { Name:'st1child', Id:7, age:'2', num:'342222222', Email:'v@gmail.com' }, ]
    },
    { Name:'st1', age:'2', Id:3, num:'342222222', Email:'v@gmail.com' },
    { Name:'st1', age:'2', Id:4, num:'342222222', Email:'v@gmail.com' },
    { Name:'st1', age:'2', Id:5, num:'342222222', Email:'v@gmail.com' },
];
const isExpandedDefault = false;
const flatIt = (data, level) => data.reduce((acc, row) => [...acc, Object.assign(row, {
    level,
    expanded: isExpandedDefault,
}), ...flatIt(row.children || [], level + 1)], []);
data = flatIt(data, 1);
<!-- parent.html -->
<template>
   <table class="slds-tree">
       <thead>
           <th>Name</th>

           <th>Age</th>

           <th>Num</th>

           <th>Email</th>
       </thead>
       <tbody>
           <template for:each={datas} for:item="d">
                <c-child key={d.Id} data={d}></c-child>
           </template>
       </tbody>

   </table>
</template>
// Child.js
export default class Child extends LightningElement {
    @track _data;

    renderedCallback() {

    }

    @api
    set data(value) {
        this._data = value;
        this.ariaExpanded = false;
        this.ariaLevel = value.level;
    }

    get data() {
        return this._data;
    }
}
Related Topic