Salesforce interview prep · Part 5 of 7

Lightning Web Components (LWC) Interview Questions

LWC vs Aura, decorators, component communication, calling Apex with @wire or imperatively, lifecycle hooks and Lightning Data Service - with code.

By Bhanu Pratap SinghLast reviewed 2026-10-2316 min read7 questions3 Beginner4 Intermediate
Level

LWC questions test two things: that you know standard modern JavaScript, and that you know where Salesforce adds to it - decorators, wire adapters, Lightning Data Service and its security model.

Q1BeginnerLWCAura

What is LWC, and how is it different from Aura?

1What it is

Lightning Web Components is Salesforce's UI framework built on web standards: custom elements, shadow DOM, ES modules and plain JavaScript classes. Aura is the older framework, with its own component model.

2Why it matters

Because LWC leans on what the browser already does, it is faster, lighter and familiar to any JavaScript developer. It is Salesforce's recommended way to build new UI; Aura remains for older components.

3Example

LWCAura
Based onWeb standards (custom elements, ES modules)Salesforce's own framework
PerformanceFaster - less framework code in the browserHeavier
FilesHTML template, JS class, XML config, optional CSSComponent, controller, helper, renderer and more
TogetherAn LWC can sit inside AuraAn Aura component cannot sit inside an LWC

4In short - say this in the interview

LWC is the standards-based UI framework - custom elements, shadow DOM and ES modules - so it is faster and plain JavaScript. Aura is the older proprietary model. Build new components in LWC; an LWC can live inside Aura, but not the other way round.

Common mistake

Saying LWC replaces Aura everywhere today. A few features still need Aura, and the two coexist.

Likely follow-ups
  • What files make up an LWC bundle?
  • What does shadow DOM mean for your CSS?
Q2BeginnerLWCDecoratorsReactivity

What do @api, @track and @wire do?

1What it is

Decorators that add Salesforce behaviour to class fields. @api makes a property or method public, so a parent can set or call it. @track makes a field re-render when the inside of an object or array changes. @wire connects a field or function to data from a wire adapter or Apex.

2Why it matters

Every field in an LWC is already reactive when you reassign it, so @track is only needed for mutations inside objects and arrays. @api is the component's public contract; @wire is how it gets data without writing fetch code.

3Example

cart.js · JavaScript
import { LightningElement, api, track, wire } from 'lwc';
import getProducts from '@salesforce/apex/ProductController.getProducts';

export default class Cart extends LightningElement {
    @api customerId;          // set by the parent: <c-cart customer-id={id}>
    total = 0;                // reactive: reassigning re-renders
    @track items = [];        // @track: items.push() re-renders too

    @wire(getProducts) products;   // data arrives in products.data / products.error

    add(item) {
        this.items.push(item);
        this.total += item.price;
    }
}

4In short - say this in the interview

@api makes a property or method public to the parent, @wire binds a field to data from an adapter or cacheable Apex, and @track makes changes inside objects and arrays re-render - plain fields are already reactive when reassigned.

Common mistake

Changing an @api property from inside the child. It belongs to the parent - copy it into a private field, or tell the parent with an event.

Likely follow-ups
  • Why are @api property names camelCase in JS but kebab-case in HTML?
  • When is @track still needed?
Q3IntermediateLWCEvents

How do Lightning Web Components communicate with each other?

1What it is

Three ways, by relationship. Parent to child: set the child's @api properties or call its @api methods. Child to parent: dispatch a CustomEvent that the parent listens for. Unrelated components: publish and subscribe on a Lightning Message Service channel.

2Why it matters

Data flows down and events flow up, which keeps each component independent. Lightning Message Service covers components that share no parent - even across LWC, Aura and Visualforce on the same page.

3Example

Parent componentChild component@apipropertyCustomEventdispatchEventAny other componentMessage channelLightning Message ServicepublishsubscribeDown with @api, up with events, sideways with Lightning Message Service.
itemTile.js - the child tells its parent · JavaScript
import { LightningElement, api } from 'lwc';

export default class ItemTile extends LightningElement {
    @api item;   // set by the parent

    handleClick() {
        this.dispatchEvent(new CustomEvent('select', { detail: { id: this.item.Id } }));
    }
}
itemList.html - the parent listens · HTML
<template>
    <template for:each={items} for:item="item">
        <c-item-tile key={item.Id} item={item} onselect={handleSelect}></c-item-tile>
    </template>
</template>

4In short - say this in the interview

Down with @api properties and methods, up with CustomEvents the parent handles with an on-handler, and between unrelated components with Lightning Message Service. Data flows down, events flow up.

Common mistake

Naming the event with uppercase letters or an "on" prefix. Event names are lowercase; the parent adds "on" - onselect for an event called select.

Likely follow-ups
  • What do the bubbles and composed options do?
  • What replaced the old pubsub module? (Lightning Message Service.)
Q4IntermediateLWCApex

@wire or imperative Apex - which do you use?

1What it is

@wire calls an Apex method automatically, caches the result and re-runs when a reactive parameter changes. Imperative calls are ordinary function calls you make yourself, for example on a button click.

2Why it matters

@wire suits reading data that should follow the page - it needs @AuraEnabled(cacheable=true), and cacheable methods cannot change data. Anything that saves, or must run only on demand, is an imperative call.

3Example

ContactController.cls · Apex
public with sharing class ContactController {
    @AuraEnabled(cacheable=true)             // required for @wire; no DML allowed
    public static List<Contact> getContacts(Id accountId) {
        return [SELECT Id, Name, Email FROM Contact WHERE AccountId = :accountId WITH USER_MODE];
    }

    @AuraEnabled                             // not cacheable: may change data
    public static void markPrimary(Id contactId) { /* update ... */ }
}
contactList.js · JavaScript
import { LightningElement, api, wire } from 'lwc';
import { refreshApex } from '@salesforce/apex';
import getContacts from '@salesforce/apex/ContactController.getContacts';
import markPrimary from '@salesforce/apex/ContactController.markPrimary';

export default class ContactList extends LightningElement {
    @api recordId;
    @wire(getContacts, { accountId: '$recordId' }) contacts;   // '$' = re-run when it changes

    async handleMark(event) {
        await markPrimary({ contactId: event.target.dataset.id });   // imperative
        await refreshApex(this.contacts);                            // reload the wired data
    }
}

4In short - say this in the interview

@wire for reading data that should load and refresh automatically - it needs cacheable=true and cannot do DML. Imperative calls for saves, or anything that runs on a user action, followed by refreshApex if wired data must update.

Common mistake

Marking a method that updates records as cacheable=true so it can be wired. Cacheable methods are not allowed to run DML.

Likely follow-ups
  • Why the $ in '$recordId'?
  • How do you handle errors from a wire? (Check the error property, or use a wired function.)
Q5IntermediateLWCLifecycle

What are the LWC lifecycle hooks?

1What it is

Methods the framework calls as a component lives: constructor() when it is created, connectedCallback() when it is added to the page, renderedCallback() after each render, disconnectedCallback() when it is removed, and errorCallback() in a parent when a child throws.

2Why it matters

Each hook has its job. Loading data or subscribing belongs in connectedCallback; touching the rendered DOM belongs in renderedCallback; cleaning up belongs in disconnectedCallback - or you leak subscriptions.

3Example

constructor()connectedCallback()renderrenderedCallback()no DOM yetload data herecan run many timesdisconnectedCallback()errorCallback()removed: clean upin a parent: a child threw

Parent and child together: parent constructor and connectedCallback, then the child's constructor, connectedCallback and renderedCallback, and finally the parent's renderedCallback - children render first.

4In short - say this in the interview

constructor on creation, connectedCallback when inserted into the page - where you load data - renderedCallback after every render, disconnectedCallback for clean-up, and errorCallback in a parent to catch a child's error.

Common mistake

Setting a reactive field inside renderedCallback without a guard. Each change re-renders, which calls renderedCallback again - an endless loop.

Likely follow-ups
  • Why can you not read child elements in the constructor?
  • Where do you subscribe to a message channel?
Q6IntermediateLWCLDS

What is Lightning Data Service, and when do you use it instead of Apex?

1What it is

Lightning Data Service reads and saves single records without Apex, through base components like lightning-record-form and adapters like getRecord and updateRecord. It shares one cache across every component on the page.

2Why it matters

It needs no Apex and no test class, it respects the user's sharing, object and field permissions automatically, and when one component saves a record, every other component showing it updates.

3Example

No Apex at all · HTML
<template>
    <lightning-record-form record-id={recordId} object-api-name="Account"
        fields={fields} mode="view"></lightning-record-form>
</template>
Reading one field with getRecord · JavaScript
import { LightningElement, api, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import NAME from '@salesforce/schema/Account.Name';

export default class AccountName extends LightningElement {
    @api recordId;
    @wire(getRecord, { recordId: '$recordId', fields: [NAME] }) account;

    get name() { return getFieldValue(this.account.data, NAME); }
}

4In short - say this in the interview

Lightning Data Service reads and writes records without Apex - lightning-record-form, getRecord, updateRecord - with security enforced and a shared cache that keeps every component in sync. Use Apex when you need queries across many records or complex logic.

Common mistake

Writing an Apex method just to show one record's fields. LDS does it with no code to test.

Likely follow-ups
  • What is the difference between lightning-record-form, -view-form and -edit-form?
  • Why import field references from @salesforce/schema?
Q7BeginnerLWCTemplates

How do you render conditionally and loop over a list in an LWC template?

1What it is

Templates use directives: lwc:if, lwc:elseif and lwc:else for conditions, and for:each with for:item (plus a unique key) to repeat markup for each item.

2Why it matters

Templates hold no expressions - logic lives in the JavaScript class as getters - which keeps markup simple and fast. The key lets the framework update only the rows that changed.

3Example

contactList.html · HTML
<template>
    <template lwc:if={isLoading}>
        <lightning-spinner alternative-text="Loading"></lightning-spinner>
    </template>
    <template lwc:elseif={error}>
        <p class="slds-text-color_error">{error}</p>
    </template>
    <template lwc:else>
        <template for:each={contacts} for:item="c">
            <p key={c.Id}>{c.Name}</p>
        </template>
    </template>
</template>

4In short - say this in the interview

lwc:if, lwc:elseif and lwc:else for conditions, and for:each with for:item and a unique key for lists. Conditions are plain properties or getters in the JS class - the template itself has no expressions.

Common mistake

Leaving out the key, or using the array index as the key. Use a stable unique value such as the record Id.

Likely follow-ups
  • What replaced if:true and if:false?
  • When would you use iterator instead of for:each?

Answers describe documented behaviour, checked against the sources listed. Platforms change between releases - confirm limits and versions before an interview.