How To Add Toggle Button For LWC Lightning Datatable?

In Salesforce LWC data tables, the toggle button is used to represent the checkbox or boolean field values in the data table column. Although a toggle button is a Boolean data type, displaying it as a toggle button directly on the data table is not supported.

To display a toggle icon, we need to create a custom type that defines the attributes to display the toggle button. In this Salesforce tutorial, we will learn how to add a toggle button in LWC lightning data table.

Add a Toggle Button For LWC Lightning Datatable

In the example below, I will create a lightning datatable with dynamically fetching the contact records. In the contact object, we have a checkbox field, Do Not Call, that will be displayed in the data table as a toggle button column.

To access the checkbox field, ensure its field visibility is enabled for the profiles. To enable the field visibility, go to Object Manager > object (contact)> fields and relationships > select field > Set field level security.

To display the toggle button, you must have a checkbox(boolean) field in the object that you will use in the Lightning Data Table.

Now, follow the steps below to create an LWC data table with a button column.

  1. Create a controller class for the object including the checkbox field using the code below.
public with sharing class LWCInlineToggle {
@AuraEnabled(Cacheable=true)
public static List<Contact> getContacts() {
return [
SELECT Id, Name, FirstName, LastName, Phone, Email, DoNotCall
FROM Contact
ORDER BY CreatedDate
];
}
}
  1. To define the toggle button logic and UI for a single toggle switch, we need to create a separate LWC component toggleType. Consider this as a helper component that we will refer to in the main LWC component.

Enter the code below in the JS file for the LWC component.

import { LightningElement, api, track } from 'lwc';

export default class Toggeltype extends LightningElement {
    @api value;
    @api context;
    @track togglevalue;

    renderedCallback() {
        this.togglevalue = this.value;
    }

    handleChange(event) {
        event.preventDefault();
        let value = event.target.checked;
        this.value = value;
        this.togglevalue = value;

        const toggel = new CustomEvent('toggelselect', {
            composed: true,
            bubbles: true,
            cancelable: true,
            detail: {
                data: { 
                    context: this.context, 
                    value: this.value 
                }
            }
        });
        this.dispatchEvent(toggel);
    }
}
  1. After this, enter the code below in toggleType.html to define the UI of the toggle button.
<template>
    <div class="slds-form-element">
        <label class="slds-checkbox_toggle slds-grid">
            <span class="slds-form-element__label slds-m-bottom_none"></span>
            <input 
                type="checkbox" 
                name="checkboxtoggle" 
                value={togglevalue} 
                checked={togglevalue} 
                onchange={handleChange}/>
            <span id="checkboxtoggle" class="slds-checkbox_faux_container">
                <span class="slds-checkbox_faux"></span>
                <span class="slds-checkbox_on">Enabled</span>
                <span class="slds-checkbox_off">Disabled</span>
            </span>
        </label>
    </div>
</template>

The checkboxtoggle will display text Enabled and Disabled when we check and uncheck the toggle button.

  1. After handling the toggle button’s UI, create another LWC component that will handle the logic to integrate the toggle button column into the data table.

Enter the code below in the customdtTypeLwc.js

import LightningDatatable from 'lightning/datatable';
import toggelTemplate from './toggelTemplate.html';

export default class CustomDtTypeLwc extends LightningDatatable {
    static customTypes = {
        toggel: {
            template: toggelTemplate,
            standardCellLayout: true,
            typeAttributes: ['value', 'context']
        }
    };
}
  1. Within the same LWC component, create a separate HTML file and enter the code below.
<template>
    <c-toggeltype 
        value={typeAttributes.value} 
        context={typeAttributes.context}>
    </c-toggeltype>
</template>

This template is required to define how the toggle column looks and its functionality in the data table.

It embeds the toggle type component with the right data, enabling a custom toggle switch for each row. Without it, the data table wouldn’t know how to display the toggle type.

  1. Create an LWC component and enter the code below in the HTML file, this component is going ot be the main component that we will deploy on the lightning page.

The HTML template below will render the data table and the toggle button for the boolean field.

<template>
    <lightning-card title="Adding custom toggle type">
        <template if:true={contacts}>
            <c-custom-dt-type-lwc
                key-field="Id"
                data={contacts}
                columns={columns}
                draft-values={saveDraftValues}
                onsave={handleSave}
                ontoggelselect={handletoggelselect}
                oncellchange={handleCellChange}
                oncancel={handleCancel}
                hide-checkbox-column
                show-row-number-column>
            </c-custom-dt-type-lwc>
        </template>
    </lightning-card>
</template>
  1. After this, enter the code below in the JS file that will handle the logic to display the checkbox field as a toggle icon, and the click event and save event to save the updated value of the checkbox field.

While changing the toggle to true or false, we have to handle two updates: update the toggle value in the data table, and update the checkbox field value in the object record.

First, in the import methods, we import the apex class getContacts. The updateRecord is a lightning function that updates the records. We also used the built-in utility ShowToastEvent, which will display a message of successful updates and errors.

import { LightningElement, wire, track } from 'lwc';
import getContacts from '@salesforce/apex/LWCInlineCtrl.getContacts';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';

const columns = [
    {
        label: 'Name',
        fieldName: 'Name',
        type: 'text',
    },
    {
        label: 'Do Not Call',
        fieldName: 'DoNotCall',
        type: 'toggel',
        editable: true,
        typeAttributes: {
            value: { fieldName: 'DoNotCall' },
            context: { fieldName: 'Id' }
        }
    }
];

export default class Extended_inline_datatable extends LightningElement {
    columns = columns;
    @track contacts;
    @track saveDraftValues = [];

    @wire(getContacts)
    contactData(result) {
        if (result.data) {
            this.contacts = JSON.parse(JSON.stringify(result.data));
        }
        if (result.error) {
            this.contacts = undefined;
        }
    }

    updateColumnData(updatedItem) {
        let copyData = JSON.parse(JSON.stringify(this.contacts));
        copyData.forEach(item => {
            if (item.Id === updatedItem.Id) {
                for (let field in updatedItem) {
                    item[field] = updatedItem[field];
                }
            }
        });
        this.contacts = [...copyData];
    }

    updateDraftValuesAndData(updateItem) {
        let draftValueChanged = false;
        let copyDraftValues = [...this.saveDraftValues];

        copyDraftValues.forEach(item => {
            if (item.Id === updateItem.Id) {
                for (let field in updateItem) {
                    item[field] = updateItem[field];
                }
                draftValueChanged = true;
            }
        });

        this.saveDraftValues = draftValueChanged ? 
            [...copyDraftValues] : 
            [...copyDraftValues, updateItem];
    }

    handletoggelselect(event) {
        event.stopPropagation();
        let toggleId = event.detail.data.context;
        let toggleValue = event.detail.data.value;
        
        let updatedItem = { 
            Id: toggleId, 
            DoNotCall: toggleValue 
        };
        
        this.updateDraftValuesAndData(updatedItem);
        this.updateColumnData(updatedItem);
    }

    handleSave(event) {
        this.saveDraftValues = event.detail.draftValues;
        const recordInputs = this.saveDraftValues.map(draft => {
            const fields = Object.assign({}, draft);
            return { fields };
        });

        const promises = recordInputs.map(recordInput => updateRecord(recordInput));
        Promise.all(promises)
            .then(() => {
                this.ShowToast('Success', 'Records Updated Successfully!', 'success', 'dismissable');
                this.saveDraftValues = [];
                return this.refresh();
            })
            .catch(error => {
                this.ShowToast('Error', 'An Error Occurred!', 'error', 'dismissable');
            })
            .finally(() => {
                this.saveDraftValues = [];
            });
    }

    ShowToast(title, message, variant, mode) {
        const evt = new ShowToastEvent({
            title: title,
            message: message,
            variant: variant,
            mode: mode
        });
        this.dispatchEvent(evt);
    }

    async refresh() {
        await refreshApex(this.contacts);
    }
}

In the columns array, we defined a custom type for the Do Not Call checkbox field using typeAttributes to bind its value to DoNotCall and its context to the record ID, with editable: true, we allow updates in the field value.

The event updateColumnData method refreshes the UI when a toggle changes. It copies this.contacts, finds the matching record by ID, updates its fields with values from updatedItem, and reassigns the updated array to this.contacts to trigger a re-render of the updated values.

At last, the handletoggelselect method fetches the Id and toggleValue from the event, creates an updatedItem, and calls updateDraftValuesAndData and updateColumnData to track and show the change.

The handleSave method uses event.detail.draftValues, formats it for updateRecord, and saves it. It shows a success toast and refreshes it on success or an error on failure, then clears saveDraftValues.

  1. At last, make the main LWC component available for the Lightning page by entering the code below in the meta.xml file.
<isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
  1. Deploy the main LWC component to the Lightning app page. There, you will see the data table with the toggle button column deployed.
Add toggle button in Salesforce LWC data table

From the data table, we can change and update the values with the toggle button. After the save, we will see a success message on the screen, and the changes will also be reflected in the record field.

Add Toggle button Columns in LWC data table

This way, we can add a toggle button column to the LWC data table in Salesforce by following the above steps.

Conclusion

In this Salesforce tutorial, we have learned to add a toggle button to Salesforce LWC data table since the lightning-datatable doesn’t natively support toggle buttons for boolean fields. To add a toggle button column, we created a custom LightningDatatable type and a main LWC to render the table and handle updates.

By executing the code from the above steps, you can efficiently enable toggling to update both the UI and records, with toast notification messages.

You may also like to read:

Agentforce in Salesforce

DOWNLOAD FREE AGENTFORCE EBOOK

Start with AgentForce in Salesforce. Create your first agent and deploy to your Salesforce Org.

Salesforce flows complete guide

FREE SALESFORCE FLOW EBOOK

Learn how to work with flows in Salesforce with 5 different real time examples.