Skip to main content

How to Dynamically Style Salesforce LWC Datatables with Custom CSS

In plain words: Dynamic styling in an LWC datatable means altering cell colors, badges, and fonts based on each row's underlying record data (such as painting an Error row red or a Success row green) at runtime.

Standard Salesforce Lightning Web Components isolate CSS using the Shadow DOM. To style tabular cells conditionally based on record values—like rendering status indicators, alerts, or audit badges—developers can map calculated CSS classes dynamically through JavaScript getters or custom data structures.

Prerequisites

  • A Salesforce Developer Edition, Scratch Org, or Sandbox environment.
  • Salesforce CLI (sf) installed and authenticated.
  • Understanding of Lightning Design System (SLDS) utility classes and JavaScript mapping methods.

Step 1: Set Up the LWC Project & Component

CLI Setup:
# Create project directory
sf project generate -n lwc-datatable-styling
cd lwc-datatable-styling

# Create LWC component
sf lightning generate component -n dataTableStyling -d force-app/main/default/lwc --type lwc

Step 2: Build the Dynamic CSS Rules

Open dataTableStyling.css. Define the styling rules for container layout and semantic cell classes:

:host {
    display: block;
}

.table-wrapper {
    background-color: #ffffff;
    border: 1px solid #e5e5e5;
    border-radius: 6px;
    overflow: hidden;
}

/* Base custom badge indicators */
.badge {
    display: inline-block;
    padding: 2px 10px;
    font-size: 0.75rem;
    font-weight: 700;
    border-radius: 12px;
    text-transform: uppercase;
}

.badge-error {
    background-color: #fce4e4;
    color: #c23934;
    border: 1px solid #ea001e;
}

.badge-warning {
    background-color: #fff2cc;
    color: #8c4b00;
    border: 1px solid #fe9339;
}

.badge-success {
    background-color: #e2efda;
    color: #2e844a;
    border: 1px solid #45c65a;
}
Warning Trap: Because of the Shadow DOM boundary in LWC, global CSS in a parent component cannot penetrate standard child components like lightning-datatable directly unless you apply custom column types or use SLDS utility tokens with the cellAttributes.class configuration property.

Step 3: Implement the JavaScript Controller Logic

In dataTableStyling.js, compute each row's badge styling dynamically by transforming the raw dataset using a getter:

import { LightningElement } from 'lwc';

export default class DataTableStyling extends LightningElement {
    rawRecords = [
        { id: 'REC-001', name: 'Invoice Processing Pipeline', status: 'Error', amount: '$12,450' },
        { id: 'REC-002', name: 'Identity Verification Queue', status: 'Warning', amount: '$4,300' },
        { id: 'REC-003', name: 'Monthly Payment Reconciliation', status: 'Success', amount: '$89,100' },
        { id: 'REC-004', name: 'Customer Onboarding Sync', status: 'Success', amount: '$1,200' }
    ];

    get formattedRows() {
        return this.rawRecords.map(record => {
            const normalizedStatus = record.status.toLowerCase();
            let badgeClass = 'badge ';

            if (normalizedStatus === 'error') {
                badgeClass += 'badge-error';
            } else if (normalizedStatus === 'warning') {
                badgeClass += 'badge-warning';
            } else if (normalizedStatus === 'success') {
                badgeClass += 'badge-success';
            }

            return {
                ...record,
                statusClass: badgeClass
            };
        });
    }
}

Step 4: Build the HTML Table Template

In dataTableStyling.html, loop over the formatted rows and bind the computed class properties:

<template>
    <lightning-card title="System Operations Monitor" icon-name="standard:service_report">
        <div class="slds-p-around_medium">
            <div class="table-wrapper">
                <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_striped">
                    <thead>
                        <tr class="slds-line-height_reset">
                            <th scope="col"><div class="slds-truncate" title="Process Name">Process Name</div></th>
                            <th scope="col"><div class="slds-truncate" title="Amount">Amount</div></th>
                            <th scope="col"><div class="slds-truncate" title="Status">Status</div></th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={formattedRows} for:item="row">
                            <tr key={row.id} class="slds-hint-parent">
                                <td><div class="slds-truncate">{row.name}</div></td>
                                <td><div class="slds-truncate">{row.amount}</div></td>
                                <td>
                                    <span class={row.statusClass}>{row.status}</span>
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </div>
        </div>
    </lightning-card>
</template>
360 Architecture Summary:
  • Data Separation: Keep raw data decoupled from presentation logic by transforming objects in getters.
  • SLDS Integration: Leverage built-in Salesforce Lightning Design System table markup (slds-table, slds-table_bordered) for native platform look and feel.
  • Standard Datatables: When using lightning-datatable, use cellAttributes: { class: { fieldName: 'statusClass' } } to pass classes directly into column metadata.

Step 5: Deploy and Verify

Deployment Routine:
# Deploy to the authenticated org
sf project deploy start

# Open target org in browser
sf org open
  • Add the component to a Lightning Page or App Page in Lightning App Builder.
  • Confirm that each record displays its styled status badge corresponding to its state.
Core Takeaway: Pre-computing style classes inside JavaScript getters enables clean, reactive, and easily maintainable conditional styling across all LWC tabular data views.