Svelte 5 Debounced Input Component - Optimize Search Performance
This example demonstrates a reusable debounced input component in Svelte 5 that delays updates to prevent excessive API calls during user typing. The debounce technique waits for a pause in user input before triggering actions, making it ideal for search inputs and real-time filtering.
Key advantages:
- Performance: Reduces API calls from every keystroke to only when user pauses typing
- Server load: Minimizes unnecessary requests and bandwidth usage
- User experience: Prevents flickering results and provides smoother interactions
- Reusability: Component can be dropped into any form with configurable delay timing
The debounce
method
export function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
}
DebouncedInput.svelte
<script lang="ts">
import { debounce } from '$lib';
let { debouncedValue = $bindable(), initialValue, ...props } = $props();
const update = debounce((v: string) => (debouncedValue = v), 300);
let value = $state(initialValue);
$effect(() => update(value));
</script>
<input type="text" bind:value {...props} />
Usage
<script lang="ts">
import DebouncedInput from './DebouncedInput.svelte';
let searchTerm = $state('');
let results = $state([]);
let loading = $state(false);
$effect(async () => {
if (!searchTerm.trim()) {
results = [];
return;
}
loading = true;
try {
const response = await fetch(`/api/search?q=${encodeURIComponent(searchTerm)}`);
results = await response.json();
} catch (error) {
console.error('Search failed:', error);
results = [];
} finally {
loading = false;
}
});
</script>
<DebouncedInput
bind:debouncedValue={searchTerm}
placeholder="Search..."
class="w-full px-3 py-2 border rounded"
/>
{#if loading}
<p>Searching...</p>
{:else if results.length > 0}
<ul>
{#each results as result}
<li>{result.title}</li>
{/each}
</ul>
{/if}