Source Code
<div class="container py-5 d-flex justify-content-center">
<div class="card bsnores-card">
<div class="card-body p-3">
<input type="search" class="form-control mb-3" id="bsnoresInput" placeholder="Search integrations...">
<ul class="list-unstyled mb-0" id="bsnoresList"></ul>
<div class="text-center py-4 d-none" id="bsnoresEmpty">
<p class="fw-semibold mb-1">No results for “<span id="bsnoresQuery"></span>”</p>
<p class="small text-muted mb-3">Try a different spelling, or clear your search to see everything.</p>
<button type="button" class="btn btn-sm btn-outline-secondary" id="bsnoresClear">Clear search</button>
</div>
</div>
</div>
</div>.bsnores-card { width: 380px; max-width: 100%; border: 1px solid #eceef1; border-radius: 14px; }
.bsnores-item { display: flex; align-items: center; gap: 10px; padding: 8px 6px; border-radius: 8px; font-size: 13.5px; }
.bsnores-item:hover { background: #f8f9fb; }
.bsnores-dot { width: 8px; height: 8px; border-radius: 50%; background: #6366f1; flex-shrink: 0; }const ITEMS = ['Slack', 'Notion', 'Figma', 'GitHub', 'Jira', 'Zoom', 'Stripe', 'Linear', 'Zendesk', 'HubSpot'];
const input = document.getElementById('bsnoresInput');
const list = document.getElementById('bsnoresList');
const empty = document.getElementById('bsnoresEmpty');
const queryEl = document.getElementById('bsnoresQuery');
function render() {
const q = input.value.trim();
const matches = q === '' ? ITEMS : ITEMS.filter(name => name.toLowerCase().includes(q.toLowerCase()));
if (matches.length === 0) {
list.innerHTML = '';
list.classList.add('d-none');
empty.classList.remove('d-none');
queryEl.textContent = q;
return;
}
empty.classList.add('d-none');
list.classList.remove('d-none');
list.innerHTML = matches.map(name =>
'<li class="bsnores-item"><span class="bsnores-dot"></span>' + name + '</li>'
).join('');
}
input.addEventListener('input', render);
document.getElementById('bsnoresClear').addEventListener('click', () => {
input.value = '';
render();
input.focus();
});
render();Bootstrap No Search Results State — Free HTML CSS JS Snippet
Bootstrap No Search Results State · Misc · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Bootstrap No Search Results State — HTML, CSS & JavaScript

A "no results" state and a generic "nothing here yet" empty state look similar but mean opposite things — one says the data doesn't exist, the other says the data exists but the current search didn't find it. This snippet keeps that distinction sharp by echoing the exact, unmodified query back into the message: queryEl.textContent = q inside render() means the empty state always says "No results for 'xyz'" using the literal text the user typed, not a generic "no items found" that leaves them wondering whether their search even registered.
render() is the single function driving every visible state — it filters ITEMS by a case-insensitive substring match, and then either populates the list or reveals the empty block based on matches.length, so the list and the empty state are structurally guaranteed to never both show at once (unlike toggling them from two separate code paths that could fall out of sync). Clearing an empty input on load intentionally returns every item rather than nothing, since an empty query means "no filter applied yet," not "search for the empty string."
"Clear search" does two things a lot of clear buttons skip: it calls render() immediately so the full list reappears without waiting for another keystroke, and it calls input.focus() afterward so a user can start a new search right away instead of having to click back into the field themselves.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Hand this snippet to an AI coding assistant like Claude and ask it to add a "Did you mean...?" suggestion using a simple edit-distance check against the item list when a search comes up empty, or to highlight the matching substring within each visible result the way bootstrap-search-autocomplete-suggestions does.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a Bootstrap 5.3 searchable list with a proper no-results state, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble it.
Requirements:
- A search input above a list of at least 8 sample items, filtering the list live on every keystroke with a case-insensitive substring match.
- An empty search query must show every item, not zero items — empty means "no filter," not "search for nothing."
- When the current query matches zero items, hide the list entirely and show an empty-state block that echoes the user's exact search text back in a message like: No results for "xyz".
- Include a "Clear search" button in the empty state that resets the input, immediately re-renders the full list, and returns keyboard focus to the search field.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Load the snippetAll ten integrations appear in a plain list, with the empty state hidden.
- 2Type a real match like "fig"The list narrows live to just "Figma" as you type.
- 3Type something that matches nothing, like "asdf"The list disappears and a message reads exactly: No results for "asdf".
- 4Click "Clear search"The input empties, the full list of ten reappears immediately, and the cursor returns to the search field.
- 5Clear the field manually with backspace insteadThe full list reappears the same way, confirming an empty query always means "show everything."
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
A generic empty state (see bootstrap-empty-state-placeholder) means the underlying data itself doesn't exist yet — an empty inbox, a fresh account. This state means the data exists, but the user's specific search term matched none of it, which is why echoing their exact query back is the important detail here.
An empty query represents "no filter has been applied," which is different from "search for an empty string." Treating it as no filter matches how virtually every real search box behaves before a user has typed anything.
No — with only ten in-memory items, filtering on every keystroke is effectively instant. For a real search hitting a network request, wrap the render() call in the same debounce pattern used in bootstrap-form-autosave-status before firing the actual request.
Yes. Keep ITEMS and the query in component state, derive matches with the same filter logic inside the render function or a computed value, and conditionally render either the list or the empty-state block based on matches.length — no other logic needs to change.
Anywhere — it uses String.includes(), so searching "hub" correctly matches "HubSpot" even though the match isn't at the start of the name. Swap to startsWith() if you specifically want prefix-only matching instead.