Master Your Salesforce Interview: 15 Real-World LWC Scenarios

Welcome to SalesforceHours! Facing a technical interview for a Salesforce Developer role can be daunting. It’s not just about knowing the syntax; it’s about applying your knowledge to solve real business problems. That’s where we come in.

This article isn’t just another list of questions. We’ve crafted 15 practical, scenario-based challenges that mirror what you’ll actually encounter in an interview and on the job. We’ll break down each problem, provide clean code solutions, and, most importantly, explain the “why” behind the code. Let’s build your confidence and turn that interview into a job offer!

Scenario 1: Designing a Dashboard with Reusable Widgets (Parent-to-Child Communication)

Scenario: Imagine you’re building a “Sales Leader Dashboard.” The main component needs to display a list of top-performing Account records. For each Account, you must show a summary card with its Name, Industry, and Annual Revenue. To keep the code clean and reusable, this summary card must be its own child component. How would you pass the data for each Account from the main dashboard component down to the individual summary card components?

The Solution: The key is to create a public property in the child component using the @api decorator. This decorator makes the property accessible from the parent, allowing data to be passed down.

Parent Component: accountDashboard.html

<template>
    <lightning-card title="Top Accounts Dashboard">
        <div class="slds-m-around_medium">
            <template for:each={contacts} for:item="con">
                <!-- Each contact is passed to the child's 'contact' property -->
                <c-contact-card key={con.Id} contact={con}></c-contact-card>
            </template>
        </div>
    </lightning-card>
</template>

Parent Component: accountDashboard.js

import { LightningElement, track } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';

export default class AccountDashboard extends LightningElement {
    @track contacts = [];
    @track error;

    connectedCallback() {
        getContacts()
            .then(result => {
                this.contacts = result;
            })
            .catch(error => {
                this.error = error;
                console.error('Error fetching contacts:', error);
            });
    }
}

Child Component: contactCard.js

import { LightningElement, api } from 'lwc';

export default class ContactCard extends LightningElement {
    // The @api decorator makes this property public and available for the parent to set.
    @api contact;
}

Child Component: contactCard.html

<template>
    <div class="slds-box slds-m-around_small slds-p-around_medium">
        <p><strong>Name:</strong> {contact.Name}</p>
        <p><strong>Email:</strong> {contact.Email}</p>
    </div>
</template>

Explanation

This is the fundamental pattern for one-way data flow in LWC. The parent component owns the data and passes it down to its children. Using @api in the child component is like creating a formal contract that says, “I can accept a ‘contact’ record.” This makes your contactCard component highly reusable anywhere you need to display a contact.

Scenario 2: Notifying a Parent Component of an Action (Child-to-Parent Communication)

Scenario: In our “Sales Leader Dashboard,” each contactCard child component has a “View Details” button. When a user clicks this button, the parent accountDashboard component needs to know which contact was selected so it can display that contact’s full information in a separate, detailed view. How would you communicate this button click event from the child card back up to the parent dashboard?

The Solution: You’ll use a CustomEvent to send a message from the child to the parent. The child dispatches the event, and the parent listens for it.

Child Component: childComponent.js

import { LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {
  handleClick() {
    const notifyEvent = new CustomEvent('notify', {
        detail: { message: 'A button on the child was clicked!' } 
    });
    this.dispatchEvent(notifyEvent);
  }
}

Child Component: childComponent.html

<template>
    <lightning-button label="Notify Parent" onclick={handleClick}></lightning-button>
</template>

Parent Component: parentComponent.js

import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ParentComponent extends LightningElement {
  handleNotification(event) {
    const message = event.detail.message;
    const toastEvent = new ShowToastEvent({
        title: 'Notification Received!',
        message: message,
        variant: 'info',
    });
    this.dispatchEvent(toastEvent);
  }
}

Parent Component: parentComponent.html

<template>
    <c-child-component onnotify={handleNotification}></c-child-component>
</template>

Explanation

LWC enforces a one-way data flow (parent to child). To communicate upwards, components send events. The child isn’t directly calling a method in the parent; it’s simply shouting, “Hey, something happened!” using dispatchEvent. The parent can choose to listen for that specific shout (onnotify) and react accordingly. This decouples the components, making them more maintainable.

Scenario 3: Automatic, Real-Time Data Loading (@wire and Apex)

Scenario: You need to create a component for a service agent’s homepage that shows a read-only list of the 10 most recently created Account records. This data must load automatically when the component appears and should be refreshed if the underlying data changes. How would you efficiently fetch this data from Salesforce using an Apex method?

The Solution: Use the @wire decorator to connect an Apex method to a property in your component. The Lightning Web Components framework handles the server call, caching, and provisioning the data or error.

Apex Controller: AccountController.cls

public with sharing class AccountController {
  @AuraEnabled(cacheable=true)
  public static List<Account> getAccounts() {
    return [
        SELECT Id, Name, Industry 
        FROM Account 
        ORDER BY CreatedDate DESC 
        LIMIT 10
    ];
  }
}

LWC: accountList.js

import { LightningElement, wire } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';

export default class AccountList extends LightningElement {
  @wire(getAccounts)
  accounts;
}

LWC: accountList.html

<template>
    <lightning-card title="Recent Accounts (Wired)" icon-name="standard:account">
        <div class="slds-m-around_medium">
            <template if:true={accounts.data}>
                <template for:each={accounts.data} for:item="acc">
                    <p key={acc.Id}>{acc.Name}{acc.Industry}</p>
                </template>
            </template>
            <template if:true={accounts.error}>
                <p>Error loading accounts.</p>
            </template>
        </div>
    </lightning-card>
</template>

Explanation

@wire is the declarative and most efficient way to fetch read-only data. The “reactive” nature means if another component on the page updates an Account record, the Lightning Data Service can automatically push the fresh data to your component, triggering a re-render without you writing any extra code. This makes it perfect for displaying lists of data that need to be up-to-date.

Scenario 4: Displaying Data in a Standard Table (Lightning Datatable)

Scenario: A sales manager requires a clean, sortable table view of their assigned Contact records. The table needs to display the Contact’s Name, Email, and Phone number and must match the standard Salesforce Lightning look and feel. What is the most efficient way to build this UI?

The Solution: Use the base lightning-datatable component. It’s a powerful and highly optimized component for displaying tabular data with built-in features like sorting, resizing, and row selection.

Apex Controller: ContactController.cls

public with sharing class ContactController {
  @AuraEnabled(cacheable=true)
  public static List<Contact> getContacts() {
    return [
        SELECT Id, Name, Email, Phone 
        FROM Contact 
        WITH SECURITY_ENFORCED
        LIMIT 20
    ];
  }
}

LWC: contactTable.js

import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';

const COLUMNS = [
  { label: 'Name', fieldName: 'Name', type: 'text' },
  { label: 'Email', fieldName: 'Email', type: 'email' },
  { label: 'Phone', fieldName: 'Phone', type: 'phone' }
];

export default class ContactTable extends LightningElement {
  columns = COLUMNS;
  contacts;
  error;

  @wire(getContacts)
  wiredContacts({ error, data }) {
    if (data) {
      this.contacts = data;
      this.error = undefined;
    } else if (error) {
      this.error = error;
      this.contacts = undefined;
    }
  }
}

LWC: contactTable.html

<template>
    <lightning-card title="Contact List" icon-name="standard:contact">
        <div style="height: 300px;">
            <lightning-datatable
                key-field="Id"
                data={contacts}
                columns={columns}
                hide-checkbox-column="true">
            </lightning-datatable>
        </div>
    </lightning-card>
</template>

Explanation

Reinventing the wheel is slow and error-prone. lightning-datatable provides a robust, accessible, and mobile-responsive table out-of-the-box. By simply defining your column metadata and providing a data array, you get a rich user experience that would take days to build from scratch.

Scenario 5: Dynamically Showing and Hiding UI Sections (Conditional Rendering)

Scenario: On a new Order form component, you have a checkbox labeled “Is this a gift?”. When a user checks this box, an additional section must appear on the screen, allowing them to enter a gift message. When unchecked, this section should disappear. How do you implement this dynamic UI behavior?

The Solution: Use the if:true (or if:false) directive in your component’s HTML template. This directive will add or remove a block of HTML from the DOM based on the value of a boolean property.

LWC: conditionalExample.js

import { LightningElement, track } from 'lwc';

export default class ConditionalExample extends LightningElement {
  @track isGift = false;

  handleToggle(event) {
    this.isGift = event.target.checked;
  }
}

LWC: conditionalExample.html

<template>
    <lightning-card title="Order Form" icon-name="standard:orders">
        <div class="slds-m-around_medium">
            <lightning-input 
                type="checkbox" 
                label="Is this a gift?" 
                onchange={handleToggle}>
            </lightning-input>

            <template if:true={isGift}>
                <div class="slds-m-top_medium">
                    <lightning-textarea label="Enter your gift message"></lightning-textarea>
                </div>
            </template>
        </div>
    </lightning-card>
</template>

Explanation

Conditional rendering is fundamental for creating interactive and responsive user interfaces. The if:true directive is highly efficient because it physically adds or removes the HTML from the page. This is better than simply hiding it with CSS (display: none), especially for large or complex sections, as it keeps the DOM lighter and improves rendering performance.

Scenario 6: User-Initiated Data Calls (Imperative Apex)

Scenario: You are building a data export component. Instead of loading a potentially massive list of Opportunity records when the component first loads (which would be slow), you need to provide a “Generate Report” button. Only when the user clicks this button should the component call Apex to fetch the data. How do you implement this user-initiated data request?

The Solution: Call the Apex method imperatively. Unlike the automatic @wire service, an imperative call gives you direct control over when the server is contacted.

Apex Controller: OpportunityController.cls

public with sharing class OpportunityController {
  @AuraEnabled
  public static List<Opportunity> getOpportunities() {
    return [
        SELECT Id, Name, StageName, Amount 
        FROM Opportunity 
        WHERE Amount != null
        ORDER BY Amount DESC
        LIMIT 50
    ];
  }
}

LWC: opportunityImperative.js

import { LightningElement, track } from 'lwc';
import getOpportunities from '@salesforce/apex/OpportunityController.getOpportunities';

export default class OpportunityImperative extends LightningElement {
  @track opportunities;
  @track error;

  handleLoad() {
    getOpportunities()
      .then(result => {
        this.opportunities = result;
        this.error = undefined;
      })
      .catch(error => {
        this.error = error;
        this.opportunities = undefined;
      });
  }
}

LWC: opportunityImperative.html

<template>
    <lightning-card title="Opportunity Report" icon-name="standard:opportunity">
        <div class="slds-m-around_medium">
            <lightning-button 
                label="Generate Report" 
                onclick={handleLoad}
                variant="brand">
            </lightning-button>

            <template if:true={opportunities}>
                <ul class="slds-m-top_medium">
                    <template for:each={opportunities} for:item="opp">
                        <li key={opp.Id}>{opp.Name}{opp.StageName} (${opp.Amount})</li>
                    </template>
                </ul>
            </template>
        </div>
    </lightning-card>
</template>

Explanation

You choose an imperative Apex call over @wire when:

  1. You need to control exactly when the call happens (e.g., on a button click, not component load).
  2. You need to call a method that performs a DML operation (insert, update, delete), as these methods cannot be cacheable=true and thus cannot be used with @wire.
  3. You need to chain a sequence of calls together.

Scenario 7: Capturing and Reflecting User Input (Data Binding)

Scenario: You’re building a live search filter. As a user types into a “Search” input field, you want to display their query in real-time right below it, like: “Searching for: [user’s text]“. How do you bind the input field’s value to a property and display it dynamically?

The Solution: You achieve this by listening to the onchange event of the input field. In the event handler, you update a component property with the new value from the input. LWC’s reactive engine automatically re-renders the part of the template that displays this property.

LWC: inputBinding.js

import { LightningElement, track } from 'lwc';

export default class InputBinding extends LightningElement {
  @track searchQuery = '';

  handleNameChange(event) {
    this.searchQuery = event.target.value;
  }
}

LWC: inputBinding.html

<template>
    <lightning-card title="Live Search Filter">
        <div class="slds-m-around_medium">
            <lightning-input 
                label="Enter Search Term" 
                value={searchQuery} 
                onchange={handleNameChange}>
            </lightning-input>
            
            <p class="slds-m-top_small">
                <strong>Searching for:</strong> {searchQuery}
            </p>
        </div>
    </lightning-card>
</template>

Explanation

This demonstrates the one-way data flow in LWC. The data flows from the component’s property (searchQuery) to the input’s value. When the user types, the onchange event fires, and your JavaScript handler updates the property. This property change triggers LWC’s reactivity system, which automatically updates the UI elements (both the input value and the <p> tag) that depend on it.

Scenario 8: Tapping into the Component Lifecycle (Lifecycle Hooks)

Scenario: Imagine you need to perform two specific actions in your component:

  1. The moment the component is added to the page, you need to fetch initial data from an external (non-Salesforce) API.
  2. After the component has finished rendering and all its child elements are on the screen, you need to initialize a third-party charting library. Which lifecycle hooks are appropriate for these two distinct actions?

The Solution: You would use connectedCallback() for the initial data fetch and renderedCallback() for the DOM manipulation.

LWC: lifecycleExample.js

import { LightningElement } from 'lwc';

export default class LifecycleExample extends LightningElement {
  
  hasRendered = false;

  connectedCallback() {
    console.log('Component Connected! Firing one-time setup.');
    // Example: fetch('https://my-external-api.com/data');
  }

  renderedCallback() {
    if (this.hasRendered) {
        return;
    }
    this.hasRendered = true;
    console.log('Component Rendered! Safe to perform DOM manipulation now.');
    // Example: initializeChartingLibrary(this.template.querySelector('div.chart'));
  }
}

LWC: lifecycleExample.html

<template>
  <p>Check the browser console for lifecycle hook logs.</p>
  <div class="chart"></div>
</template>

Explanation

  • connectedCallback(): This is your “on-init” hook. It runs once when the component is placed on the page. It’s the ideal place for setup tasks that don’t rely on the component’s child elements being rendered.
  • renderedCallback(): This hook runs after the render phase. It’s the place to be when you need to be certain that the HTML is on the page and you can safely query for elements (this.template.querySelector) or integrate with libraries that need to manipulate the DOM. Caution: This hook can fire multiple times. Always use a boolean flag (hasRendered) to prevent your logic from running unnecessarily and causing infinite loops.

Scenario 9: Refreshing Cached Data After a Change (Refresh Apex)

Scenario: You have a component displaying a list of Tasks fetched with @wire. On the same component, you have a form to quickly add a new Task. After the user successfully submits the form and creates a new Task via an imperative Apex call, the wired list of tasks must be automatically updated to show the new entry—without a full page reload. How do you force the wired data to refresh?

The Solution: Use the refreshApex function from the @salesforce/apex module. This function tells the Lightning Data Service that the data provisioned by a specific @wire call is stale and needs to be fetched again from the server.

LWC: refreshExample.js

import { LightningElement, track, wire } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
import createAccount from '@salesforce/apex/AccountController.createAccount';
import { refreshApex } from '@salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class RefreshExample extends LightningElement {
  @track accounts;
  wiredAccountsResult;

  @wire(getAccounts)
  wiredAccounts(result) {
    this.wiredAccountsResult = result;
    if (result.data) {
      this.accounts = result.data;
    }
  }

  handleCreateAccount() {
    createAccount({ accountName: 'Refreshed Account' })
      .then(() => {
        this.dispatchEvent(
          new ShowToastEvent({ title: 'Success', message: 'Account created', variant: 'success' })
        );
        return refreshApex(this.wiredAccountsResult);
      })
      .catch(error => {
        // Handle error
      });
  }
}

LWC: refreshExample.html

<template>
    <lightning-button label="Create New Account & Refresh" onclick={handleCreateAccount}></lightning-button>
    <template if:true={accounts}>
        <ul>
            <template for:each={accounts} for:item="acc">
                <li key={acc.Id}>{acc.Name}</li>
            </template>
        </ul>
    </template>
</template>

Explanation

The @wire service uses a client-side cache for performance. When you perform a DML operation (like creating a record) using a separate, imperative Apex call, the wire service’s cache doesn’t automatically know the data on the server has changed. refreshApex is the bridge. You pass it the result object from your wire, and it triggers a refetch, ensuring your UI always reflects the latest state of the database.

Scenario 10: Programmatic Navigation (NavigationMixin)

Scenario: In a custom lightning-datatable displaying a list of Account records, you want to make the Account Name a clickable link. When a user clicks the name, they should be redirected to that specific Account’s standard record page. How do you programmatically trigger this navigation from your LWC?

The Solution: Use the NavigationMixin. This is the standard, future-proof LWC service for handling all navigation requests. You compose it into your component and then call the this[NavigationMixin.Navigate] function with a PageReference object that defines the destination.

LWC: navigationExample.js

import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class NavigationExample extends NavigationMixin(LightningElement) {
  @api recordId = '001xx000003DHPqAAO'; // Example Account Id

  navigateToRecord() {
    this[NavigationMixin.Navigate]({
      type: 'standard__recordPage',
      attributes: {
        recordId: this.recordId,
        objectApiName: 'Account',
        actionName: 'view'
      }
    });
  }
}

LWC: navigationExample.html

<template>
    <lightning-button label="View Account Record" onclick={navigateToRecord}></lightning-button>
</template>

Explanation

Hard-coding URLs (like /lightning/r/Account/${this.recordId}/view) is a bad practice because they can break in different contexts (like a Salesforce Console or a Community). The NavigationMixin abstracts away the URL structure. You simply describe where you want to go (a record page, a list view, a custom tab) using a standard PageReference object, and the mixin generates the correct URL for the user’s current environment. This makes your component robust and portable.

Scenario 11: Creating Reusable Components with Slots

Scenario: You need to create a generic modal component. This modal should have a consistent header and footer (with “Close” and “Save” buttons), but the content inside the modal’s body should be completely customizable by any parent component that uses it. How do you design a component that can accept and render HTML content from its parent?

The Solution: Use slots. A slot is a placeholder in a component’s template that a parent component can fill with its own markup. You can use a default (unnamed) slot or multiple named slots for more complex layouts.

Child Component: customModal.html

<template>
    <section role="dialog" class="slds-modal slds-fade-in-open">
        <div class="slds-modal__container">
            <header class="slds-modal__header">
                <h2 class="slds-text-heading_medium">
                    <!-- Named slot for the title -->
                    <slot name="title">Default Modal Title</slot>
                </h2>
            </header>
            <div class="slds-modal__content slds-p-around_medium">
                <!-- Default (unnamed) slot for the main content -->
                <slot></slot>
            </div>
            <footer class="slds-modal__footer">
                <!-- Named slot for footer actions -->
                <slot name="footer">
                    <lightning-button label="Close"></lightning-button>
                </slot>
            </footer>
        </div>
    </section>
</template>

Parent Component: modalDemo.html

<template>
    <c-custom-modal>
        <!-- Content for the 'title' slot -->
        <span slot="title">Create New Contact</span>

        <!-- Content for the default slot -->
        <lightning-input label="First Name"></lightning-input>
        <lightning-input label="Last Name"></lightning-input>

        <!-- Content for the 'footer' slot -->
        <div slot="footer">
            <lightning-button label="Cancel" class="slds-m-right_x-small"></lightning-button>
            <lightning-button variant="brand" label="Save"></lightning-button>
        </div>
    </c-custom-modal>
</template>

Explanation

Slots are the key to building truly reusable and flexible components. Instead of the child component dictating all of its content, it provides a structured template with placeholders (<slot>). The parent component can then project its own content into these placeholders. This is a powerful composition pattern that separates the container (the modal’s frame) from the content (the form fields).

Scenario 12: Communicating Between Unrelated Components

Scenario: You have two components on a page that are not in a parent-child relationship: a filterControls component in the sidebar and a dataDisplay component in the main content area. When a user applies a filter in filterControls, the dataDisplay component needs to receive the filter information and update its data. How can you facilitate communication between these two sibling components?

The Solution: Use the Lightning Message Service (LMS). LMS allows components anywhere on a page to communicate through a shared Lightning Message Channel. One component publishes a message to the channel, and any component that has subscribed to that channel will receive the message.

1. Create a Message Channel: Create a file FilterMessageChannel.messageChannel-meta.xml in a messageChannels folder.

<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <masterLabel>FilterMessageChannel</masterLabel>
    <isExposed>true</isExposed>
    <description>This channel sends filter data.</description>
    <lightningMessageFields>
        <fieldName>filterValue</fieldName>
        <description>The filter value to apply</description>
    </lightningMessageFields>
</LightningMessageChannel>

2. Publisher Component: filterControls.js

import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import FILTER_MESSAGE_CHANNEL from '@salesforce/messageChannel/FilterMessageChannel__c';

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

    handleFilterChange(event) {
        const payload = { filterValue: event.target.value };
        publish(this.messageContext, FILTER_MESSAGE_CHANNEL, payload);
    }
}

3. Subscriber Component: dataDisplay.js

import { LightningElement, wire } from 'lwc';
import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService';
import FILTER_MESSAGE_CHANNEL from '@salesforce/messageChannel/FilterMessageChannel__c';

export default class DataDisplay extends LightningElement {
    subscription = null;
    receivedFilter = 'None';

    @wire(MessageContext)
    messageContext;

    connectedCallback() {
        this.subscribeToMessageChannel();
    }

    subscribeToMessageChannel() {
        if (!this.subscription) {
            this.subscription = subscribe(
                this.messageContext,
                FILTER_MESSAGE_CHANNEL,
                (message) => this.handleMessage(message)
            );
        }
    }

    handleMessage(message) {
        this.receivedFilter = message.filterValue;
        // Logic to refetch data based on the filter
    }

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

Explanation

LMS is the standard Salesforce solution for communication between components that are not directly related. It decouples the components entirely; the publisher doesn’t need to know who is listening, and the subscriber doesn’t need to know who is publishing. This makes it ideal for building complex, interactive applications where actions in one area of the page need to affect another.

Scenario 13: Handling DML Errors and Displaying Toasts

Scenario: You have a form to create a new Contact. If the Apex DML operation fails on the server (e.g., due to a validation rule failure or a trigger exception), the user must be shown a clear and user-friendly error message. How would you catch the error from an imperative Apex call and display it in a toast notification?

The Solution: Use the .catch() block of the Promise returned by the imperative Apex call. Inside the .catch() block, you can parse the error and dispatch a ShowToastEvent with the variant set to error.

Apex Controller: ContactController.cls

public with sharing class ContactController {
    @AuraEnabled
    public static Contact createContact(String lastName) {
        if (String.isBlank(lastName)) {
            // Intentionally cause an error
            throw new AuraHandledException('Last Name cannot be blank.');
        }
        Contact c = new Contact(LastName = lastName);
        insert c;
        return c;
    }
}

LWC: contactForm.js

import { LightningElement } from 'lwc';
import createContact from '@salesforce/apex/ContactController.createContact';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ContactForm extends LightningElement {
    lastName = '';

    handleNameChange(event) {
        this.lastName = event.target.value;
    }

    saveContact() {
        createContact({ lastName: this.lastName })
            .then(contact => {
                const evt = new ShowToastEvent({
                    title: 'Success',
                    message: 'Contact created with ID: ' + contact.Id,
                    variant: 'success',
                });
                this.dispatchEvent(evt);
            })
            .catch(error => {
                // This block executes if the promise is rejected
                const evt = new ShowToastEvent({
                    title: 'Error creating record',
                    // Reduce the error to a user-friendly message
                    message: error.body.message, 
                    variant: 'error',
                });
                this.dispatchEvent(evt);
            });
    }
}

Explanation

Proper error handling is critical for a good user experience. Imperative Apex calls return a JavaScript Promise, which has a .then() method for the success path and a .catch() method for the failure path. By implementing the .catch() block, you can gracefully handle server-side exceptions, extract a meaningful error message from the complex error object, and present it to the user via a toast notification, preventing a poor experience.

Scenario 14: Using the getRecord Wire Adapter

Scenario: You need to build a component that will be placed on an Account record page. This component must display the Account’s Name and AnnualRevenue without requiring a custom Apex controller. How can you fetch data from the record the component is currently on?

The Solution: Use the getRecord wire adapter from the lightning/uiRecordApi module. This is a highly efficient, built-in way to get data for a specific record. You just need to provide the recordId and the fields you want.

LWC: recordDataDisplay.js

import { LightningElement, api, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// Import references to the schema fields
import NAME_FIELD from '@salesforce/schema/Account.Name';
import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';

export default class RecordDataDisplay extends LightningElement {
    // The component gets the recordId automatically when placed on a record page
    @api recordId;

    // Wire getRecord to fetch the data
    @wire(getRecord, { recordId: '$recordId', fields: [NAME_FIELD, REVENUE_FIELD] })
    account;

    // Use getters with getFieldValue to safely access the data
    get name() {
        return getFieldValue(this.account.data, NAME_FIELD);
    }

    get revenue() {
        return getFieldValue(this.account.data, REVENUE_FIELD);
    }
}

LWC: recordDataDisplay.html

<template>
    <lightning-card title="Account Details" icon-name="standard:account">
        <div class="slds-m-around_medium">
            <template if:true={account.data}>
                <p><strong>Account Name:</strong> {name}</p>
                <p><strong>Annual Revenue:</strong> 
                    <lightning-formatted-number 
                        value={revenue} 
                        format-style="currency" 
                        currency-code="USD">
                    </lightning-formatted-number>
                </p>
            </template>
        </div>
    </lightning-card>
</template>

Explanation

The lightning/uiRecordApi module provides a standard, Apex-free way to perform CRUD operations on Salesforce records. The getRecord adapter is particularly useful because it respects user permissions, sharing rules, and field-level security automatically. It also participates in the Lightning Data Service cache, meaning if the record is updated elsewhere on the page, your component will refresh automatically. Using field imports (e.g., @salesforce/schema/Account.Name) makes your code refactor-proof against changes to field API names.

Scenario 15: Creating a Form with Custom Input Validation

Scenario: You are building a custom registration form. It has an email field and a password field. You need to enforce two validation rules before the “Submit” button is enabled:

  1. The email must be in a valid format (e.g., text@example.com).
  2. The password must be at least 8 characters long. How would you implement this custom, real-time validation logic?

The Solution: Use event handlers on the input fields to check their validity on every change. Use getters to compute boolean properties based on the validation state, and use these properties to disable the submit button and show/hide error messages.

LWC: customValidationForm.js

import { LightningElement, track } from 'lwc';

export default class CustomValidationForm extends LightningElement {
    @track email = '';
    @track password = '';
    
    // Private validation flags
    isEmailValid = false;
    isPasswordValid = false;

    handleEmailChange(event) {
        this.email = event.target.value;
        // Simple regex for email format validation
        const emailRegex = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
        this.isEmailValid = emailRegex.test(this.email);
    }

    handlePasswordChange(event) {
        this.password = event.target.value;
        this.isPasswordValid = this.password.length >= 8;
    }

    // Getter to compute if the entire form is valid
    get isFormInvalid() {
        return !this.isEmailValid || !this.isPasswordValid;
    }

    // Getter to show/hide the password error message
    get passwordError() {
        if (this.password && !this.isPasswordValid) {
            return 'Password must be at least 8 characters long.';
        }
        return '';
    }
}

LWC: customValidationForm.html

<template>
    <lightning-card title="Custom Validation Form">
        <div class="slds-m-around_medium">
            <lightning-input
                type="email"
                label="Email"
                onchange={handleEmailChange}
                required>
            </lightning-input>
            
            <lightning-input
                type="password"
                label="Password"
                onchange={handlePasswordChange}
                message-when-too-short={passwordError}
                required>
            </lightning-input>

            <lightning-button
                label="Submit"
                variant="brand"
                disabled={isFormInvalid}
                class="slds-m-top_medium">
            </lightning-button>
        </div>
    </lightning-card>
</template>

Explanation

While base lightning-input components provide some built-in validation (required, minLength, etc.), you often need more complex, custom logic. By handling the onchange event, you can run your validation logic in real-time. Using getters (get isFormInvalid()) to compute the overall form state is a clean pattern that keeps your template logic simple. The disabled attribute of the button is then reactively bound to this getter, providing a seamless user experience where the button only becomes active when all conditions are met.

Summary

Mastering these 15 scenarios will give you a powerful command of the core LWC concepts that truly matter. By understanding not just the what but the why and when, you can confidently articulate your solutions in any interview. Practice these examples, think about how they apply to different business needs, and you’ll be well on your way to demonstrating real-world proficiency in Lightning Web Components.

Also checkout our other post

Author

  • Salesforce Hours

    Salesforcehour is a platform built on a simple idea: "The best way to grow is to learn together". We request seasoned professionals from across the globe to share their hard-won expertise, giving you the in-depth tutorials and practical insights needed to accelerate your journey. Our mission is to empower you to solve complex challenges and become an invaluable member of the Ohana.


Discover more from Salesforce Hours

Subscribe to get the latest posts sent to your email.

2 thoughts on “Master Your Salesforce Interview: 15 Real-World LWC Scenarios”

Leave a Reply

Discover more from Salesforce Hours

Subscribe now to keep reading and get access to the full archive.

Continue reading