Debounced Search

Type-ahead search with debounced input and simulated API call.

Live Demo

No results for ""

Source

HTML + JavaScript
<div data-component="debounced-search">
    <input type="search" data-model="query"
           data-action="input:onSearch" data-event-debounce="400">
    <span data-show="searching" class="loading-spinner"></span>

    <div data-show="query && !searching && results.length > 0"
         data-list="results">
        <template>
            <div>
                <span data-bind="name"></span>
                <span data-bind="email"></span>
            </div>
        </template>
    </div>
    <div data-show="query && !searching && results.length === 0">
        No results for "<span data-bind="query"></span>"
    </div>
</div>

<script>
wildflower.component('debounced-search', {
    state: { query: '', results: [], searching: false },
    onSearch() {
        if (!this.query) { this.results = []; return; }
        this.searching = true;
        setTimeout(() => {   // Replace with fetch()
            const q = this.query.toLowerCase();
            this.results = this._allUsers
                .filter(u => u.name.toLowerCase().includes(q));
            this.searching = false;
        }, 500);
    },
    _allUsers: [
        { name: 'Alice Chen',    email: 'alice@example.com' },
        { name: 'Bob Martinez',  email: 'bob@example.com' },
        { name: 'Carol Johnson', email: 'carol@example.com' }
        // ...more entries
    ]
});
</script>

Key Points

  • data-event-debounce="400" waits 400ms after the last keystroke before firing onSearch, reducing API calls dramatically
  • State updates immediately via data-model; onSearch reads this.query when it runs
  • Three conditional states: spinner while searching, results list, empty state. All controlled with data-show expressions
  • Replace the setTimeout with a real fetch(). The debouncing and state management stays identical