Episode 16 of 18
Custom Search Filter
Build a real-time search filter using vanilla JavaScript — filter a list of items as the user types, showing and hiding matches dynamically.
Custom Search Filter
One of the most useful UI patterns is a real-time search filter. As the user types, matching items are shown and non-matching items are hidden. You will build this with pure vanilla JavaScript.
The HTML
<div class="search-container">
<input type="text" id="search" placeholder="Search ninjas...">
<ul id="ninja-list">
<li>Ryu</li>
<li>Ken</li>
<li>Yoshi</li>
<li>Mario</li>
<li>Luigi</li>
<li>Peach</li>
</ul>
</div>
The JavaScript
var searchInput = document.querySelector('#search');
var items = document.querySelectorAll('#ninja-list li');
searchInput.addEventListener('input', function() {
var searchTerm = this.value.toLowerCase();
items.forEach(function(item) {
var text = item.textContent.toLowerCase();
if (text.includes(searchTerm)) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
How It Works
User types "yu"
↓
input event fires
↓
Get search term: "yu"
↓
Loop through all <li> elements:
"ryu" → includes "yu" → display: block ✓
"ken" → no match → display: none ✗
"yoshi" → includes "yu"?→ no ✗
...
Adding a No Results Message
searchInput.addEventListener('input', function() {
var searchTerm = this.value.toLowerCase();
var visibleCount = 0;
items.forEach(function(item) {
var text = item.textContent.toLowerCase();
if (text.includes(searchTerm)) {
item.style.display = 'block';
visibleCount++;
} else {
item.style.display = 'none';
}
});
var noResults = document.querySelector('.no-results');
if (visibleCount === 0) {
noResults.style.display = 'block';
} else {
noResults.style.display = 'none';
}
});
Key Takeaways
- Use the
inputevent for real-time filtering as the user types - Convert both the search term and item text to lowercase for case-insensitive matching
- Toggle
display: none/blockto show or hide elements - This is a fundamental pattern — no frameworks needed