Salesforce Lightning Web Components (LWC) provide a modern, high-performance web framework for building responsive user interfaces on the Salesforce platform. In this guide, we will step through creating a real-time, dynamic record search component using LWC and Apex.
Prerequisites
Before writing the component code, ensure your environment is configured with the following requirements:
- Salesforce Developer Org: A active developer sandbox or scratch org.
- Salesforce CLI: Installed on your local machine for deployments.
- IDE: Visual Studio Code with the Salesforce Extension Pack installed.
Step-by-Step Implementation
Step 1: Create a New Lightning Web Component
Open your terminal in VS Code and run the following Salesforce CLI command to generate a new component named CustomSearch:
sf project generate component -n CustomSearch -d force-app/main/default/lwc --type lwc
Step 2: Edit the HTML Markup
Open CustomSearch.html and replace its contents with the following markup:
<template>
<lightning-card title="Custom Search" icon-name="standard:search">
<div class="slds-m-around_medium">
<lightning-input
type="search"
label="Enter search keyword"
onchange={handleSearchTermChange}>
</lightning-input>
</div>
<div class="slds-m-around_medium">
<template if:true={searchResults}>
<ul class="slds-list_dotted">
<template for:each={searchResults} for:item="result">
<li key={result.Id}>{result.Name}</li>
</template>
</ul>
</template>
<template if:false={searchResults}>
<p>No results found.</p>
</template>
</div>
</lightning-card>
</template>
Step 3: Edit the JavaScript Controller
Open CustomSearch.js and configure the reactive properties and wire service callout:
import { LightningElement, track, wire } from 'lwc';
import searchRecords from '@salesforce/apex/CustomSearchController.searchRecords';
export default class CustomSearch extends LightningElement {
@track searchTerm = '';
@track searchResults;
handleSearchTermChange(event) {
this.searchTerm = event.target.value;
}
@wire(searchRecords, { searchTerm: '$searchTerm' })
wiredSearchResult({ error, data }) {
if (data) {
this.searchResults = data;
} else if (error) {
console.error('Error retrieving search results:', error);
}
}
}
$ prefix when passing reactive variables to wire services (e.g., '$searchTerm') prevents the wire service from automatically re-evaluating when the input value updates.
Step 4: Create the Apex Controller Class
Create an Apex class named CustomSearchController.cls to handle the backend database query:
public with sharing class CustomSearchController {
@AuraEnabled(cacheable=true)
public static List<Account> searchRecords(String searchTerm) {
if (String.isBlank(searchTerm)) {
return new List<Account>();
}
String searchKey = '%' + searchTerm + '%';
return [SELECT Id, Name FROM Account WHERE Name LIKE :searchKey LIMIT 10];
}
}
cacheable=true on @AuraEnabled Apex methods called via LWC wire adapters to optimize client-side performance and reduce unnecessary server requests.
Step 5: Deploy the Code to Your Salesforce Org
Deploy the component and class source files using the CLI:
sf project deploy start --source-dir force-app
Step 6: Add Component to Lightning App Builder
- Navigate to Setup > User Interface > Lightning App Builder.
- Select an existing Account Record Page or create a new App Page.
- Locate
CustomSearchunder custom components and drag it onto the canvas. - Save and activate the page.
- UI Layer: Native Lightning Design System (SLDS) tags with dynamic iteration.
- Controller: Reactive wire adapter bound to state variables via
'$searchTerm'. - Backend:
with sharingenforcement with cached SOQL query filters.
Conclusion
Building custom search capabilities with Lightning Web Components yields responsive, scalable solutions on Salesforce. By leveraging LWC wire services alongside cacheable Apex endpoints, developers maintain optimal client performance while retrieving data dynamically.