Skip to main content

How to Apply Dynamic Styling in Salesforce LWC (Classes, Getters & CSS Variables)

In plain words: Dynamic styling in Lightning Web Components (LWC) refers to modifying the colors, sizes, or layout of UI elements at runtime based on user actions, record data, or business logic. In Salesforce LWC, this is achieved by binding reactive JavaScript getters to the HTML class attribute or dynamically setting CSS custom properties (variables).

Building responsive, user-friendly Lightning interfaces often requires visual cues like alert states, interactive toggles, or dynamic status badges. In this tutorial, you will learn standard, platform-compliant patterns for handling dynamic styling in LWC without violating Shadow DOM encapsulation.

Prerequisites

  • A Salesforce Developer Edition, Sandbox, or Scratch Org.
  • Salesforce CLI (sf) configured in your workspace.
  • Familiarity with standard LWC reactivity and JavaScript getters.

Step 1: Set Up the Component Structure

Generate the LWC bundle using the Salesforce CLI:
sf lightning generate component -n dynamicStylingDemo -d force-app/main/default/lwc --type lwc

Step 2: Define Component Styles in CSS

In LWC, standard component styles placed in dynamicStylingDemo.css are automatically scoped to the component's Shadow DOM. There is no need to manually import the CSS file inside your JavaScript code.

:host {
    display: block;
}

/* Base button wrapper styling */
.action-box {
    padding: 1rem;
    border-radius: 8px;
    transition: all 0.3s ease-in-out;
}

/* Dynamic theme states */
.theme-default {
    background-color: #f3f3f3;
    border: 1px solid #d8dde6;
    color: #181818;
}

.theme-active {
    background-color: #e2efda;
    border: 1px solid #a9d18e;
    color: #375623;
}

.theme-alert {
    background-color: #fce4e4;
    border: 1px solid #e06666;
    color: #7a1414;
}
Warning Trap: Avoid writing manual CSS imports like import styles from './component.css' or using static static styles = [styles] in standard on-platform LWC. The Salesforce build compiler automatically links your same-named CSS file (<componentName>.css) to your template at build time.

Step 3: Implement Reactive Styling Logic in JavaScript

Open dynamicStylingDemo.js. Use tracked state properties and clean JavaScript getters to calculate and return CSS class strings dynamically:

import { LightningElement } from 'lwc';

export default class DynamicStylingDemo extends LightningElement {
    currentStatus = 'default'; // 'default', 'active', 'alert'

    // Getter computing dynamic class string based on state
    get boxClass() {
        let dynamicClass = 'action-box ';
        if (this.currentStatus === 'active') {
            dynamicClass += 'theme-active';
        } else if (this.currentStatus === 'alert') {
            dynamicClass += 'theme-alert';
        } else {
            dynamicClass += 'theme-default';
        }
        return dynamicClass;
    }

    get statusLabel() {
        return this.currentStatus.toUpperCase();
    }

    setNormal() {
        this.currentStatus = 'default';
    }

    setActive() {
        this.currentStatus = 'active';
    }

    setAlert() {
        this.currentStatus = 'alert';
    }
}

Step 4: Build the HTML Template

In dynamicStylingDemo.html, bind the container's class attribute directly to your reactive {boxClass} getter:

<template>
    <lightning-card title="Dynamic Styling in LWC" icon-name="utility:brush">
        <div class="slds-p-around_medium">
            
            <!-- Dynamic Container -->
            <div class={boxClass}>
                <h3 class="slds-text-heading_small slds-m-bottom_x-small">
                    Current Component State: <strong>{statusLabel}</strong>
                </h3>
                <p>The background, border, and font colors update automatically as state changes.</p>
            </div>

            <!-- Interactive Controls -->
            <div class="slds-m-top_medium slds-button-group" role="group">
                <lightning-button label="Default" onclick={setNormal}></lightning-button>
                <lightning-button variant="success" label="Active State" onclick={setActive}></lightning-button>
                <lightning-button variant="destructive" label="Alert State" onclick={setAlert}></lightning-button>
            </div>

        </div>
    </lightning-card>
</template>
360 Architecture Summary:
  • Class Getters: Preferred method for toggling predefined CSS classes based on component data state.
  • CSS Custom Properties: Use style="--custom-color: {dynamicColor}" when colors or pixel values must be calculated arbitrarily from runtime data.
  • Shadow DOM Boundary: Scoped CSS rules within an LWC will not leak into or affect parent or sibling components on the page.

Step 5: Expose and Deploy the Component

Update dynamicStylingDemo.js-meta.xml to expose the component to Lightning App Builder:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>60.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
Deploy & Verify:
# Deploy the component bundle
sf project deploy start

# Open target org in browser
sf org open
  • In Salesforce Setup, navigate to Lightning App Builder.
  • Drop dynamicStylingDemo onto any test page layout, save, and activate.
  • Click the action buttons to see instant, reactive CSS theme switching in real time.
Core Takeaway: Using JavaScript getters bound to the template's class attribute provides a clean, reactive, and maintainable approach to dynamic styling that adheres directly to Salesforce Shadow DOM standards.