implementing autocomplete and smart suggestions in jekyll search
Adding Smart Search to Your Knowledge Base
Autocomplete and smart suggestions are key UX features that help users discover content quickly. When implemented well, they reduce bounce rates and improve time on site. In this final installment, we’ll build a feature-rich autocomplete system that works with your existing Jekyll setup and requires no backend.
Why Autocomplete Matters
- Provides immediate feedback on what’s searchable
- Reduces user typing effort
- Surfaces relevant content before a full search is triggered
With a static JSON index and a bit of JavaScript, you can create this experience entirely on the client side and host it for free on GitHub Pages.
Preparing Your Search Index for Autocomplete
Your search index should include titles and excerpts, since those are most relevant for quick suggestions. Here’s an example:
[
{% assign docs = site.guides | concat: site.faqs %}
{% for doc in docs %}
{
"title": "{{ doc.title | escape }}",
"url": "{{ doc.url | relative_url }}",
"excerpt": {{ doc.content | markdownify | strip_html | truncatewords: 20 | jsonify }},
"tags": {{ doc.tags | jsonify }}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
Keep this index lightweight—no need to include full content if your main goal is to surface suggestions while typing.
Setting Up the Autocomplete UI
Use a simple input and container for showing results:
Style the results to match your theme and ensure they are keyboard navigable.
Building the Autocomplete Logic
Here’s a basic autocomplete engine using JavaScript. It filters on the fly and highlights matches:
let searchData = [];
fetch('/search.json')
.then(res => res.json())
.then(data => searchData = data);
document.getElementById('autocomplete-input').addEventListener('input', function() {
const query = this.value.toLowerCase();
const matches = searchData.filter(entry => entry.title.toLowerCase().includes(query));
showSuggestions(matches.slice(0, 5)); // Limit to 5 suggestions
});
function showSuggestions(results) {
const list = document.getElementById('autocomplete-results');
list.innerHTML = "";
results.forEach(item => {
const li = document.createElement("li");
li.innerHTML = "<a href='" + item.url + "'>" + highlightQuery(item.title) + "</a>";
list.appendChild(li);
});
}
function highlightQuery(text) {
const query = document.getElementById('autocomplete-input').value;
return text.replace(new RegExp(`(${query})`, 'gi'), "<strong>$1</strong>");
}
This is a minimal example, but it forms the base for a powerful UX.
Adding Fuzzy Matching for Better Suggestions
To improve flexibility, use libraries like Fuse.js for fuzzy matching:
const fuse = new Fuse(searchData, {
keys: ['title', 'excerpt', 'tags'],
threshold: 0.3
});
document.getElementById('autocomplete-input').addEventListener('input', function() {
const query = this.value;
const results = fuse.search(query).slice(0, 5);
showSuggestions(results.map(r => r.item));
});
This allows typos and partial matches to still produce useful suggestions, which improves the success rate for users significantly.
Supporting Keyboard Navigation
Enhance accessibility by letting users navigate results via keyboard:
let selectedIndex = -1;
document.getElementById('autocomplete-input').addEventListener('keydown', function(e) {
const items = document.querySelectorAll("#autocomplete-results li");
if (e.key === "ArrowDown") {
selectedIndex = (selectedIndex + 1) % items.length;
updateHighlight(items);
} else if (e.key === "ArrowUp") {
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
updateHighlight(items);
} else if (e.key === "Enter" && selectedIndex > -1) {
items[selectedIndex].querySelector('a').click();
}
});
function updateHighlight(items) {
items.forEach((item, i) => item.classList.toggle("highlight", i === selectedIndex));
}
This makes the experience more intuitive and works well with screen readers.
Integrating Smart Suggestions from Tags and Categories
You can also precompute suggestion lists from your tags or categories and match them against user input:
const tagSuggestions = [...new Set(searchData.flatMap(doc => doc.tags))];
document.getElementById("autocomplete-input").addEventListener("input", function() {
const input = this.value.toLowerCase();
const relatedTags = tagSuggestions.filter(tag => tag.toLowerCase().startsWith(input));
renderTagHints(relatedTags);
});
This hybrid approach helps both new and returning users quickly navigate your documentation.
Performance Tips for Large Indexes
- Lazy-load the search index after page load
- Throttle input events (e.g. debounce by 200ms)
- Use session storage to cache the index
Also consider compressing your search.json using Gzip on build if you deploy to Netlify or Cloudflare Pages.
Using Third-Party Libraries (Optional)
Popular libraries for autocomplete in static sites:
- Fuse.js for fuzzy logic
- autoComplete.js for a plug-and-play UI
- Algolia Autocomplete (can be used offline with static index)
These libraries handle edge cases, accessibility, and UI patterns without reinventing the wheel.
Conclusion
Autocomplete and smart suggestions can dramatically enhance the usability of your Jekyll-powered knowledge base. With the right structure, you can build this feature entirely on the client side using JSON, JavaScript, and free hosting via GitHub Pages.
This completes our 7-part series on building a fully interactive, searchable knowledge base using Jekyll collections, Liquid templates, and browser-based search engines. Whether you're managing technical docs or a product FAQ, this stack offers performance, flexibility, and sustainability—without needing a dynamic backend.
Now your knowledge base isn’t just static—it’s smart, fast, and made to grow.