Skip to main content

How to Build Dynamic Search Functionality in LWC

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.

In plain words: Dynamic search in LWC captures input keystrokes, passes the search term to an Apex controller method, and updates the displayed record list instantly on screen without reloading the page.
Dynamic Search

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
        ];
    }
}
Developer Trap: SOQL Injection & Limits: Always sanitize raw search strings using 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'):

Reactive Wire Pattern: Prefixing property variables with a dollar sign ('$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;
    }
}
Key Summary: Dynamic Search Architecture
  • UI Input: Capture real-time keystrokes using onchange on lightning-input.
  • Apex Annotation: Mark Apex method @AuraEnabled(cacheable=true) to allow reactive wire service binding.
  • Reactive Wiring: Use reactive syntax ('$searchKey') in @wire to 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.