STEP 1
How Live Search Works
Live search uses the input event: it fires every single time the value inside an input changes. That means it triggers with each keystroke, not just when the user presses Enter.
Inside the event listener, you:
- Read the current value of the search input
- Convert it to lowercase with
.toLowerCase()
- Loop through every card
- Read the card's name and description text with
.textContent
- Convert that to lowercase too
- Check if it includes the search term using
.includes()
- Show the card if it matches, hide it if not
Why toLowerCase on both sides?
If someone types "cedar" but the card says "Cedar", a direct comparison would fail. Converting both to lowercase first makes the search case-insensitive. Same query, same result regardless of capitalization.
STEP 2
Add the Search Bar CSS
๐ Add to CSS (before #directory):
.search-bar {
margin-bottom: 24px;
position: relative;
}
.search-bar input {
width: 100%;
padding: 14px 20px 14px 48px;
border: 2px solid #e8e2d8;
border-radius: 100px;
font-family: var(--font-body);
font-size: 1rem;
color: var(--pine);
outline: none;
background: white;
transition: border-color 0.2s;
}
.search-bar input:focus { border-color: var(--sage); }
.search-icon { position: absolute; left: 18px; top: 50%; transform: translateY(-50%); font-size: 1.125rem; pointer-events: none; }
STEP 3
Add the Search Bar HTML
Above the filter bar, add the search input:
๐ Add above .filter-bar:
<div class="search-bar">
<span class="search-icon">๐</span>
<input type="text" id="searchInput" placeholder="Search businesses, nations, categories...">
</div>
STEP 4
Add the Search JavaScript
Inside your <script> block, after the filter code, add:
๐ Add to <script> (after filter code):
document.getElementById('searchInput').addEventListener('input', function() {
var query = this.value.toLowerCase().trim();
cards.forEach(function(card) {
var text = card.textContent.toLowerCase();
if (text.includes(query)) {
card.style.display = '';
} else {
card.style.display = 'none';
}
});
if (query === '') {
cards.forEach(function(card) { card.style.display = ''; });
}
});
textContent reads all the visible text inside an element, including nested children. So searching "Onamia" finds the Niimi Catering card even though "Onamia" is in the footer, not the business name. The search checks the whole card.
Stage 4 Complete
Live search works. Type anything in the search box and cards filter instantly. Try searching "ojibwe", "cloquet", or "wellness" to see cards appear and disappear in real time.
Next: Stage 5 adds a featured spotlight section above the main grid.