← Back to all tutorials

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 input event 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/block to show or hide elements
  • This is a fundamental pattern — no frameworks needed