Ask Krrish Contact Us
Home
Developer & Admin
Apex Triggers Mastery Asynchronous Apex SOQL & SOSL Governor Limits Flows & Process Builder
Advanced Topics
LWC Essentials Security & Sharing Managed Packages Deployment & CI/CD Integration Patterns
Interview Prep
Available Now
Debug Log Analyzer
Coming Soon
Org Comparator Soon
Resources About Ask Krrish Contact Us

LWC Interview Questions & Lightning Web Components Guide — SFX Support

Dive into the world of Lightning Web Components (LWC), Salesforce's modern framework for building high-performance UI. This module covers LWC fundamentals, component structure, data flow, event communication, and best practices.

Need hands-on help?

1. Introduction to LWC

Lightning Web Components (LWC) represents Salesforce's modern approach to building user interfaces on the Lightning Platform. Introduced in Spring '19, LWC is a client-side JavaScript framework built on web standards, offering superior performance, a familiar development experience for web developers, and seamless integration with the Salesforce ecosystem.

What is LWC?

LWC is a lightweight, performant framework for building single-page applications and reusable UI components. It leverages modern web standards (ECMAScript 7+, Web Components, Shadow DOM) and provides a thin layer of Salesforce-specific services on top — making LWC development feel much like standard web development.

Why LWC?

  • Performance: Built on web standards, LWC is significantly faster than its predecessor Aura Components due to less framework overhead and native browser support.
  • Modern Web Standards: Familiarity for web developers, easier to learn, and aligned with industry best practices.
  • Reusability: Components are modular and reusable across different parts of your Salesforce org or Experience Cloud sites.
  • Security: Leverages Shadow DOM for encapsulation, protecting component internals from external interference.
  • Developer Productivity: Modern tooling, clear component lifecycle, and a streamlined development model.
  • Coexistence with Aura: LWC and Aura components can coexist and communicate within the same Lightning page, allowing gradual migration.

LWC is the recommended framework for building new UI components on the Salesforce platform. While Aura components are still supported, LWC offers the most benefits for future development.

2. LWC Core Concepts

At its heart, an LWC is a custom HTML element with its own JavaScript, HTML template, and CSS. These three files work together to define the component's behavior, structure, and styling.

a. Component-Based Architecture

LWC promotes a component-based architecture where UIs are broken down into small, independent, and reusable building blocks. Each component manages its own state and renders its own UI, making development modular and maintainable.

b. HTML Template (.html)

Defines the component's UI structure using standard HTML with special LWC directives. Uses a <template> tag as the root.

HTML — Template
<template>
    <div class="container">
        <h1>Hello, {greeting}!</h1>
        <button onclick={handleClick}>Change Greeting</button>
    </div>
</template>
  • {property} — Binds data from the JavaScript class to the template.
  • onclick={methodName} — Binds an event to a JavaScript method.
  • lwc:if, lwc:elseif, lwc:else — Conditional rendering.
  • for:each, for:item, for:index — Iterates over a list to render items.

c. JavaScript Class (.js)

Contains the component's logic, data, and event handlers. It's an ES6 module that imports functionalities from the lwc module.

JavaScript — Component Class
import { LightningElement, api, track } from 'lwc';

export default class HelloWorld extends LightningElement {
    @api greeting = 'World';   // Public property
    @track counter = 0;        // Reactive private property

    connectedCallback() {
        console.log('Component is connected to the DOM!');
    }

    handleClick() {
        this.counter++;
        this.greeting = 'Salesforce Developer ' + this.counter;
    }
}
  • import { LightningElement } from 'lwc'; — Imports the base class for LWC.
  • export default class ... extends LightningElement — Defines the component's JavaScript class.
  • Decorators (@api, @track, @wire) — Special annotations that add reactive or public capabilities to properties.

d. CSS (.css)

LWC uses Shadow DOM for CSS encapsulation — styles defined in a component's CSS file are scoped to that component and don't leak out or interfere with other components. This prevents style conflicts in complex applications.

CSS — Component Styles
.container {
    padding: 20px;
    border: 1px solid rgba(255,255,255,.06);
    border-radius: 8px;
    text-align: center;
}

h1 {
    color: #0070d2;
    font-size: 2em;
}

button {
    background-color: #0070d2;
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 5px;
    cursor: pointer;
}

3. LWC Component Structure

Every Lightning Web Component resides in a folder with the same name as the component, containing the HTML, JavaScript, metadata, and optionally a CSS file.

Standard Folder Structure

File Structure
force-app/main/default/lwc/
└── myComponentName/
    ├── myComponentName.html
    ├── myComponentName.js
    ├── myComponentName.css          (Optional)
    └── myComponentName.js-meta.xml
  • myComponentName.html — Defines the component's user interface.
  • myComponentName.js — Contains the component's logic, properties, and event handlers.
  • myComponentName.css — Optional scoped styles (Shadow DOM encapsulated).
  • myComponentName.js-meta.xml — Defines API version, exposure targets, and object restrictions.

Example js-meta.xml

XML — Component Metadata
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>Account</object>
                <object>Contact</object>
            </objects>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>
  • apiVersion — Specifies the API version for the component.
  • isExposed — Set to true to make the component available in Lightning App Builder or Experience Builder.
  • targets — Defines where the component can be used (App Page, Record Page, Home Page, etc.).
  • targetConfigs — Provides specific configurations per target, such as restricting usage to certain sObjects on a record page.

4. Data Flow & Decorators (@api, @track, @wire)

LWC uses decorators to enable reactivity and public properties in JavaScript classes. These are imported from the lwc module and play a crucial role in how data flows within and between components.

a. @api — Public Properties

  • Purpose: Exposes a property as public. Parent components can set its value on a child component. Changes are reactive.
  • Use Cases: Passing data down from parent to child component.
JavaScript — @api Decorator
import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api recordId;
    @api message = 'Default Message';
}
HTML — Parent Passing Props
<c-child-component record-id="001..." message="Hello from Parent"></c-child-component>

b. @track — Reactive Private Properties

  • Purpose: Makes a private property reactive so template re-renders when its value changes.
  • Important: As of Winter '20, all fields are reactive by default. Only use @track for objects or arrays when you need reactivity on their internal property changes (not just reference changes).
JavaScript — @track for Objects
import { LightningElement, track } from 'lwc';

export default class MyComponent extends LightningElement {
    @track myObject = { name: 'Initial', value: 0 };

    updateObject() {
        // Best practice: reassign to trigger reactivity clearly
        this.myObject = { ...this.myObject, value: this.myObject.value + 1 };
    }
}

c. @wire — Reactive Data Service

  • Purpose: Invokes an Apex method or UI API wire adapter and provisions data to a property or function. Automatically re-renders when underlying data changes.
  • Use Cases: Fetching records, getting picklist values, querying Apex methods reactively.
JavaScript — @wire Decorator
import { LightningElement, wire } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';

export default class AccountList extends LightningElement {
    @wire(getAccounts)
    accounts; // { data, error } auto-provisioned

    // Or use a function for more control:
    // @wire(getAccounts)
    // wiredAccounts({ error, data }) {
    //     if (data) { this.accounts = data; }
    //     else if (error) { this.error = error; }
    // }
}

5. Event Communication

Components in LWC communicate primarily through events. Understanding event flow is crucial for building interactive applications where components need to interact with each other.

a. Child-to-Parent Communication (Custom Events)

Children dispatch custom events; parents listen for them. This is the recommended way for a child to notify its parent of an action or data change.

JavaScript — Child Dispatches Event
import { LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {
    handleClick() {
        const myCustomEvent = new CustomEvent('childclick', {
            detail: { message: 'Hello from child!' },
            bubbles: true,
            composed: true
        });
        this.dispatchEvent(myCustomEvent);
    }
}
HTML — Parent Listens for Event
<template>
    <p>Message from child: {childMessage}</p>
    <c-child-component onchildclick={handleChildClick}></c-child-component>
</template>
JavaScript — Parent Handles Event
import { LightningElement, track } from 'lwc';

export default class ParentComponent extends LightningElement {
    @track childMessage = '';

    handleChildClick(event) {
        this.childMessage = event.detail.message;
    }
}

b. Parent-to-Child Communication

Parents pass data down to children using @api public properties — covered in the decorators section above.

c. Unrelated Components — Lightning Message Service (LMS)

For components not in a direct parent-child relationship (e.g., on different parts of a Lightning page), Lightning Message Service (LMS) is the recommended solution using a publish-subscribe model.

JavaScript — LMS Publisher
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import SAMPLE_MESSAGE_CHANNEL from '@salesforce/messageChannel/SampleMessageChannel__c';

export default class PublisherComponent extends LightningElement {
    @wire(MessageContext) messageContext;

    publishMessage() {
        const payload = { recordId: '001ABC', message: 'Data updated!' };
        publish(this.messageContext, SAMPLE_MESSAGE_CHANNEL, payload);
    }
}
JavaScript — LMS Subscriber
import { LightningElement, wire } from 'lwc';
import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService';
import SAMPLE_MESSAGE_CHANNEL from '@salesforce/messageChannel/SampleMessageChannel__c';

export default class SubscriberComponent extends LightningElement {
    subscription = null;
    receivedMessage = '';

    @wire(MessageContext) messageContext;

    connectedCallback() {
        this.subscription = subscribe(
            this.messageContext,
            SAMPLE_MESSAGE_CHANNEL,
            (message) => { this.receivedMessage = message.message; }
        );
    }

    disconnectedCallback() {
        unsubscribe(this.subscription);
        this.subscription = null;
    }
}

6. LWC Lifecycle Hooks

LWC components have a well-defined lifecycle, and you can tap into specific phases using lifecycle hooks — methods in the component's JavaScript class that execute at particular moments.

  • constructor() — Called when the component is created. Always call super() first. Do not access @api properties or this.template here — they are not yet initialized. Use for initializing private properties.
  • connectedCallback() — Called when the component is inserted into the DOM. Use for fetching initial data (if not using @wire), setting up event listeners, and accessing @api properties. Fires again if component is removed and reinserted.
  • renderedCallback() — Called after every render (initial and re-renders). Use for DOM manipulations or integrating third-party libraries. Be cautious — avoid updating reactive properties here without a guard condition to prevent infinite loops.
  • disconnectedCallback() — Called when the component is removed from the DOM. Use for cleanup: removing event listeners, unsubscribing from LMS to prevent memory leaks.
  • errorCallback(error, stack) — Called when an error occurs in any descendant component. Acts like a JavaScript error boundary. Use for catching/logging errors and displaying fallback UI.
JavaScript — Lifecycle Hooks Example
import { LightningElement, api } from 'lwc';

export default class LifecycleDemo extends LightningElement {
    @api recordId;

    constructor() {
        super();
        console.log('1. Constructor called');
        // Do NOT access this.recordId or this.template here
    }

    connectedCallback() {
        console.log('2. Connected Callback — Record ID:', this.recordId);
    }

    renderedCallback() {
        console.log('3. Rendered Callback');
        // Guard against infinite loops:
        // if (!this.hasRendered) { this.hasRendered = true; ... }
    }

    disconnectedCallback() {
        console.log('4. Disconnected Callback — clean up resources');
    }

    errorCallback(error, stack) {
        console.error('5. Error Callback:', error, stack);
    }
}

7. Working with Apex in LWC

LWC can interact with Salesforce data and logic stored in Apex classes — allowing complex database operations, business logic, and callouts not possible in client-side JavaScript alone.

a. Apex Method Requirements

Apex methods called by LWC must be public static and annotated with @AuraEnabled. Read-only methods should also use cacheable=true for caching and performance.

Apex — Controller Class
public with sharing class AccountController {

    @AuraEnabled(cacheable=true)
    public static List<Account> getAccounts() {
        return [SELECT Id, Name, Industry FROM Account LIMIT 10];
    }

    @AuraEnabled
    public static String createAccount(String accountName) {
        Account newAcc = new Account(Name = accountName);
        insert newAcc;
        return newAcc.Id;
    }
}

b. Calling Apex Imperatively

Use imperative calls when you need explicit control over when the Apex method executes (e.g., on a button click). Returns a Promise.

JavaScript — Imperative Apex Call
import { LightningElement } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
import createAccount from '@salesforce/apex/AccountController.createAccount';

export default class ApexImperativeDemo extends LightningElement {
    accounts;
    error;

    handleLoadAccounts() {
        getAccounts()
            .then(result => {
                this.accounts = result;
                this.error = undefined;
            })
            .catch(error => {
                this.error = error;
                this.accounts = undefined;
            });
    }

    handleCreateAccount() {
        createAccount({ accountName: 'New Imperative Account' })
            .then(result => {
                console.log('Account created with ID:', result);
                this.handleLoadAccounts(); // Refresh the list
            })
            .catch(error => {
                this.error = error;
            });
    }
}

c. Calling Apex with @wire (Reactive)

Use @wire for reactive data — it automatically refreshes when reactive parameters change. The $ prefix makes a parameter reactive.

JavaScript — @wire with Apex
import { LightningElement, api, wire } from 'lwc';
import getAccountDetails from '@salesforce/apex/AccountController.getAccountDetails';

export default class AccountDetailsWire extends LightningElement {
    @api recordId;

    @wire(getAccountDetails, { accountId: '$recordId' }) // '$' makes it reactive
    wiredAccount({ error, data }) {
        if (data) {
            this.account = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.account = undefined;
        }
    }
}

Choose imperative when you need controlled execution (button click, DML). Choose @wire for read-only reactive data that should auto-refresh.

8. LWC Best Practices

Adhering to best practices ensures your Lightning Web Components are performant, maintainable, secure, and reusable.

a. Component Granularity

  • Small, Focused Components: Design components to do one thing well. Break complex UIs into smaller, reusable child components.
  • Container vs. Presentational: Container components handle data fetching and logic; presentational components focus solely on rendering UI based on input properties.

b. Data Flow & Reactivity

  • Unidirectional Data Flow: Data flows down via @api; events flow up via custom events.
  • Minimize @track: Only use for objects/arrays needing internal property reactivity. Primitives are auto-reactive.
  • Prefer @wire for Read-Only Data: Use imperative Apex only for DML or when explicit execution control is needed.

c. Performance

  • Lazy Loading: Load data or components only when needed.
  • Minimize DOM Manipulation: Let the framework handle DOM updates. Avoid this.template.querySelector without guards in renderedCallback.
  • Optimize Apex Calls: Ensure Apex methods are bulkified and selective to avoid governor limits.

d. Security

  • Respect FLS & CRUD: LWC respects FLS and CRUD for UI API calls by default. In Apex, use with sharing and always manually check FLS and CRUD for sensitive data.
  • Sanitize User Input: Always sanitize input before using it in queries or DML operations.

e. Reusability & Maintainability

  • Clear Naming Conventions: Use consistent, descriptive names for components, properties, methods, and events.
  • Comments: Document complex logic and non-obvious parts of the code.
  • Use Lightning Base Components: Utilize standard lightning- components (e.g., lightning-button, lightning-input, lightning-datatable) — they are performant, accessible, and SLDS-compliant.

f. Testing

  • Write Jest Unit Tests: Use Jest for client-side LWC unit testing to verify component behavior in isolation.
  • Test Apex Integration: Ensure all Apex methods called by LWC are covered by Apex unit tests.

9. Conclusion & Next Steps

Lightning Web Components provide a powerful, modern, and efficient framework for building rich user interfaces on the Salesforce platform. By embracing web standards and offering robust features for data binding, event communication, and Apex integration, LWC empowers developers to create highly performant and maintainable applications.

Key Takeaways

  • Web Standards First: LWC is built on modern web standards, making it approachable for web developers.
  • Component-Based: Focus on building small, reusable, and encapsulated components.
  • Decorators are Key: Understand @api for public properties, @track for reactive objects/arrays, and @wire for reactive data provisioning.
  • Event-Driven Communication: Use custom events for child-to-parent and LMS for unrelated component communication.
  • Lifecycle Awareness: Leverage lifecycle hooks to execute code at specific points in a component's life.
  • Apex Integration: Seamlessly connect to Apex for server-side logic and data operations.
  • Best Practices: Prioritize performance, security, reusability, and thorough testing.

Mastering LWC is essential for any Salesforce developer looking to build modern, engaging, and scalable user experiences. Continue exploring the official Salesforce LWC Developer Guide and Trailhead modules for deeper dives into advanced topics and real-world scenarios.

Get Expert Help

Independent community initiative. Not affiliated with Salesforce.com, Inc.