Implementing real-time dynamic search in Salesforce Lightning Web Components (LWC) significantly improves user experience. Instead of requiring users to press a submit button, dynamic search queries database records instantly as users type their search criteria into an input field.
Step 1: Create the Component HTML Markup
Start by building an HTML template containing a lightning-input field to capture search keystrokes and an iterative loop (for:each) to render matching search results:
<!-- dynamicSearch.html -->
<template>
<lightning-card title="Dynamic Account Search" icon-name="standard:search">
<div class="slds-p-around_medium">
<lightning-input
type="search"
label="Search Accounts"
placeholder="Type account name..."
value={searchKey}
onchange={handleSearchChange}>
</lightning-input>
<div class="slds-m-top_medium">
<template if:true={searchResults}>
<ul class="slds-list_vertical slds-has-dividers_bottom-space">
<template for:each={searchResults} for:item="result">
<li key={result.Id} class="slds-item">
<p class="slds-text-body_regular">{result.Name}</p>
</li>
</template>
</ul>
</template>
<template if:true={error}>
<p class="slds-text-color_error">Error loading search records.</p>
</template>
</div>
</div>
</lightning-card>
</template>
Step 2: Implement the Apex Backend Controller
Create an Apex class with an @AuraEnabled(cacheable=true) method that executes a SOQL query using wildcards (LIKE) to find matching records:
// AccountSearchController.cls
public with sharing class AccountSearchController {
@AuraEnabled(cacheable=true)
public static List<Account> searchRecords(String searchKey) {
if (String.isBlank(searchKey)) {
return new List<Account>();
}
String key = '%' + String.escapeSingleQuotes(searchKey) + '%';
return [
SELECT Id, Name, Industry, Phone
FROM Account
WHERE Name LIKE :key
WITH USER_MODE
LIMIT 10
];
}
}
String.escapeSingleQuotes() to block SOQL injection vulnerabilities. Additionally, restrict results using LIMIT clauses to ensure responsive queries.
Step 3: Wire Apex Method in JavaScript Controller
Connect your LWC JavaScript class directly to the Apex method using the @wire service adapter with a reactive parameter ('$searchKey'):
'$searchKey') tells LWC to automatically re-execute the wired Apex call whenever searchKey updates!
// dynamicSearch.js
import { LightningElement, wire, track } from 'lwc';
import searchRecords from '@salesforce/apex/AccountSearchController.searchRecords';
export default class DynamicSearch extends LightningElement {
searchKey = '';
searchResults;
error;
// Reactive wire service re-executes whenever searchKey updates
@wire(searchRecords, { searchKey: '$searchKey' })
wiredAccounts({ data, error }) {
if (data) {
this.searchResults = data;
this.error = undefined;
} else if (error) {
this.error = error;
this.searchResults = undefined;
}
}
handleSearchChange(event) {
this.searchKey = event.target.value;
}
}
- UI Input: Capture real-time keystrokes using
onchangeonlightning-input. - Apex Annotation: Mark Apex method
@AuraEnabled(cacheable=true)to allow reactive wire service binding. - Reactive Wiring: Use reactive syntax (
'$searchKey') in@wireto trigger queries automatically upon state changes. - Performance Best Practice: Consider implementing debouncing (e.g.,
setTimeout) for high-traffic or large-scale data queries to minimize Apex governor calls.
Conclusion
Building dynamic search functionality in Lightning Web Components leverages LWC's reactive wire framework and cacheable Apex methods. By capturing user input events and wiring parameters reactively, you deliver fast, responsive record filtering with minimal boilerplate code.