Day 23: Debounced Search Input
Build a form where specific fields appear or disappear based on the user's selected answers.
JavaScript focus
- setTimeout
- clearTimeout
- Storing and resetting a timer variable (basic state)
- input event
- Event listeners
- toLowerCase()
- includes()
- Conditional logic for filtering
- Showing/hiding DOM elements
Nice extras (pick 1-2 max)
- “No results found” message
- Minimum character threshold (e.g. only search after 2 characters)
- Clear input button (reset search + list)
- Result count display (e.g. “5 results”)
MDN prep
Debounced Search Input
- Apple
- Banana
- Orange
- Grapes
- Strawberry
- Blueberry
- Mango
- Pineapple
- Watermelon
- Peach
No results found.
The HTML
<section class="section debounced_search">
<h2 class="secondary_heading">Debounced Search Input</h2>
<div class="form_field">
<label for="filter-input">Search tutorials</label>
<input type="text" id="filter-input" name="filter-input" placeholder="Search by keyword">
<button type="button" id="reset-button" class="button">Reset</button>
</div>
<ul class="card_list" id="tutorial-list">
<li class="card_item">Apple</li>
<li class="card_item">Banana</li>
<li class="card_item">Orange</li>
<li class="card_item">Grapes</li>
<li class="card_item">Strawberry</li>
<li class="card_item">Blueberry</li>
<li class="card_item">Mango</li>
<li class="card_item">Pineapple</li>
<li class="card_item">Watermelon</li>
<li class="card_item">Peach</li>
</ul>
<p class="empty_state" id="no-results-message" hidden>No results found.</p>
</section>
The JavaScript
function initDebouncedSearch() {
const root = document.querySelector(".debounced_search");
if (!root) return;
let input = root.querySelector("#filter-input");
const reset = root.querySelector("#reset-button");
const items = root.querySelectorAll(".card_item");
const empty = root.querySelector(".empty_state");
let inputTimer;
// listen for typing
input.addEventListener("input", (e) => {
// clear timer with each input
clearTimeout(inputTimer);
// when typing stops...
// timer continues
inputTimer = setTimeout(() => {
const text = e.target.value.toLowerCase().trim();
console.log(text);
const matchedItems = Array.from(items).filter((item) => {
const match = item.textContent.toLowerCase().includes(text);
if (!match) {
item.hidden = true;
} else {
item.hidden = false;
}
return match;
});
// if no matches
if (matchedItems.length === 0) {
empty.hidden = false;
} else {
empty.hidden = true;
}
}, 500);
});
// reset button
reset.addEventListener("click", () => {
clearTimeout(inputTimer);
input.value = "";
empty.hidden = true;
items.forEach((item) => {
item.hidden = false;
});
});
}
initDebouncedSearch();