The Future of Data Representation: How to Build a Viral LWC Custom Accordion Datatable

  • HTML File
<template>
        <template for:each={parentRecords} for:item="parentRecord">
          <div key={parentRecord} data-key={parentRecord} class="parentRecord" >
              <div data-key={parentRecord.id} class="slds-grid slds-wrap" style="min-height: 3rem;">
                <div class="slds-col slds-size_11-of-12 slds-align_absolute-center" style="justify-content:left;padding-left: 0.5%;">
                  {parentRecord.name}
                </div>
                <div class="slds-col slds-size_1-of-12 my-icon slds-align_absolute-center" style="justify-content:right;padding-right: 0.5%;">
                  <lightning-button-icon
                  icon-name="utility:chevrondown"
                  alternative-text= "show/hide"
                  variant="bare"
                  onclick={toggleChildRecords}
                  aura:id={parentRecord.id}
                  data-id={parentRecord.id}
                  data-div-key={parentRecord.id}
                  class="slds-m-left_x-small buttonColor-Inactive">
                </lightning-button-icon>
                </div>
            </div>
            
            <template if:true={parentRecord.showChildren}>
              <div class="childRecordMain">
              </div>
              <div class="slds-grid slds-wrap childRecordHeader">
                <div class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:left;">
                  Policy Name
                </div>
                <div class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:center;">
                  Policy Number
                </div>
                <div class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:center;">
                  Year
                </div>
                <div class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:right;">
                  Action
                </div>
              </div>
              
                <template for:each={parentRecord.children} for:item="childRecord">
                  <div key={childRecord.policyNo} class="slds-grid slds-wrap childRecordRows" >
                  <div  class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:left;">
                    {childRecord.policyName}
                  </div>
                  <div  class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:center;">
                    {childRecord.policyNo}
                  </div>
                  <div  class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:center;">
                    {childRecord.PolicyYear}
                  </div>
                  <div class="slds-col slds-size_3-of-12 slds-align_absolute-center" style="justify-content:right;">
                    <lightning-button-icon
                    icon-name="utility:download"
                    alternative-text= "donwload"
                    variant="bare"
                    onclick={toggleChildRecords}
                    data-id={childRecord.policyNo}
                    class="slds-m-left_x-small buttonColor-Inactive">
                  </lightning-button-icon>
                  </div>
                </div>
                </template>
            </template>
          </div>
        </template>
      
  </template>
  • JS File
    import { LightningElement, track } from 'lwc';

export default class DataTable extends LightningElement {
  @track parentRecords = [];
  tableHeaders = [];

  connectedCallback() {
    // Example JSON data
    const jsonData = {
      headers: ['Parent Record', 'Child Record'],
      data: [
        {
          id: '1',
          name: 'IRP5',
          children: [
            { policyNo: '001', policyName: 'policy 1' , PolicyYear:'2023'},
            { policyNo: '002', policyName: 'policy 2' , PolicyYear:'2023'}
          ]
        },
        {
          id: '2',
          name: 'IT3A',
          children: [
            { policyNo: '003', policyName: 'policy 3' , PolicyYear:'2023'},
            { policyNo: '004', policyName: 'policy 4' , PolicyYear:'2023'}
          ]
        }
      ]
    };

    this.tableHeaders = jsonData.headers;
    this.parentRecords = jsonData.data.map((item) => ({
      ...item,
      showChildren: false
    }));
  }

  toggleChildRecords(event) {

    let divKey = event.target.dataset.divKey;
    let divElement = this.template.querySelector('[data-key="' + divKey + '"]');
    if (divElement) {
      if (divElement.classList.contains('highlighted-row')){
        divElement.classList.remove('highlighted-row');
      }else{
        divElement.classList.add('highlighted-row');
      }
    }
    if (event.target.iconName == 'utility:chevrondown'){
      event.target.iconName = 'utility:chevronup';
    }else{
      event.target.iconName = 'utility:chevrondown';
    }

    if (event.target.className == 'slds-m-left_x-small buttonColor-Inactive'){
      event.target.className = 'slds-m-left_x-small buttonColor-Active';
    }else{
      event.target.className = 'slds-m-left_x-small buttonColor-Inactive';
    }

    const parentId = event.currentTarget.dataset.id;
    const updatedParentRecords = this.parentRecords.map((parentRecord) => {
      if (parentRecord.id === parentId) {
        return { ...parentRecord, showChildren: !parentRecord.showChildren };
      }
      return parentRecord;
    });
    this.parentRecords = updatedParentRecords;
    
  }
}
  • CSS File
.parentRecord{
  margin-bottom: 1% !important; 
  border-radius: 4px !important;
  box-shadow: 0px 1px 6px 0px rgba(139, 146, 167, 0.50) !important; 
  
}
.childRecordMain{
  border-top: 1px solid var(--neutral-n-200-pale-grey-200, #C5C7D2); 
  margin-top: 1%;
  margin-left: 0.5%;
  margin-right: 0.5%;
}
.childRecordHeader{
  min-height: 2.5rem; 
  padding-left: 0.5%;
  padding-right: 0.5%;
}
.childRecordRows{
  min-height: 2.5rem; 
  border-radius: 5px;
  border: 1px solid var(--neutral-n-200-pale-grey-200, #C5C7D2); 
  margin-bottom: 0.5%; 
  margin-left: 0.5%;
  margin-right: 0.5%;
}
.highlighted-row {
  background-color: #00164E !important;
  color: #FFFFFF !important;
}

.buttonColor-Inactive{
  --dxp-g-neutral-3: #002B99 !important;
}
.buttonColor-Active {
  --dxp-g-neutral-3: #FFFFFF !important;
}
  • Output


Comments