Day 07: Filterable List
Make a list of items that filters as the user types in a search field.
JavaScript focus
- input driven filtering
- looping arrays / node lists
- comparing normalized strings
- hiding/showing items
Nice extras
- “no results” message
- category tags
- clear search button
MDN prep
Filterable List
- Button Counter
- Modal Dialog
- Accordion FAQ
- Theme Toggle
- Task List
No results found.
The HTML
<section class="section filterable_list">
<h2 class="secondary_heading">Filterable List</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="reset" id="reset-button" class="button">Reset</button>
</div>
<ul class="card_list" id="tutorial-list">
<li class="card_item">Button Counter</li>
<li class="card_item">Modal Dialog</li>
<li class="card_item">Accordion FAQ</li>
<li class="card_item">Theme Toggle</li>
<li class="card_item">Task List</li>
</ul>
<p class="empty_state" id="no-results-message">No results found.</p>
</section>
The JavaScript
function initFilterableList() {
const root = document.querySelector(".filterable_list");
if (!root) return;
let input = root.querySelector("#filter-input");
const reset = root.querySelector("#reset-button");
const items = root.querySelectorAll(".card_item");
// hide the empty message on page load
const empty = root.querySelector(".empty_state");
empty.setAttribute("hidden", "");
input.addEventListener("input", (e) => {
// get text from input
let text = e.target.value;
text = text.toLowerCase().trim();
const matchedItems = Array.from(items).filter((item) => {
const match = item.textContent.toLowerCase().includes(text);
// hide list items if not matched
if (!match) {
item.setAttribute("hidden", "");
} else {
item.removeAttribute("hidden", "");
}
// reset the input and show the list items
reset.addEventListener("click", () => {
input.value = "";
item.removeAttribute("hidden", "");
empty.setAttribute("hidden", "");
});
return match;
});
// show empty message if no matches
if (matchedItems.length === 0) {
empty.removeAttribute("hidden", "");
} else {
empty.setAttribute("hidden", "");
}
});
}
initFilterableList();