Code

main.js — wiring up search

In the code column — main.js with search. We add a fourth loose variable, searchQuery, a derived visiblePictures() (the filtered pictures), and a debounced input listener.

First, index.html needs a search field:

<input type="search" id="search" placeholder="Search by title…" autocomplete="off">

The key line is the input listener wrapped in debounce:

searchInput.addEventListener('input', debounce((e) => {
  searchQuery = e.target.value.trim();
  render();                                   // filter ONLY once settled
}, 250));

And render() always draws from derived data:

function render() {
  renderGallery({ isLoading, error, pictures: visiblePictures() });
}

Verify. Serve it and type into the search box:

1. Type "moon" → the grid narrows to titles containing "moon".
2. Clear it → all pictures return.
3. Type something absent → you see "No pictures match…" (the empty state from lesson 6).

Gotcha (without debounce). Temporarily remove debounce (leave just (e) => {...}) and, in the browser's "Performance" or with console.count() inside, watch how many times render() fires while typing. Every keystroke is a full grid re-render. For local search it may "work", but the habit is bad: add server search and it becomes a flood of requests. Events that "rain down" always get wrapped in debounce.

Notice (it's piling up). We now have four loose variables: pictures, isLoading, error, searchQuery. Still manageable. But the collection (lesson 10) will add sorting, pagination, its own search… In lesson 8 we'll see where this leads.