enhancing search experience for jekyll knowledge base
Why Search UX Matters in Knowledge Bases
When building a knowledge base, providing effective search functionality is critical. A powerful search engine that is difficult or frustrating to use will drive users away. For Jekyll sites hosted on GitHub Pages, the search is typically client-side, using pre-built JSON indexes. To maximize usability, adding advanced UX features is key.
Core UX Features to Consider
- Autocomplete suggestions as users type
- Fuzzy matching to handle typos and partial words
- Instant result previews without page reloads
- Keyboard navigation support within results
- Highlighting matched terms in results
Implementing Autocomplete with Fuse.js
Fuse.js is a lightweight fuzzy-search library perfect for client-side search on static sites. It provides fuzzy matching and supports weighting fields.
Step 1 Setup Fuse.js
Add Fuse.js to your project, either by CDN or local script:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/fuse.min.js"></script>
Step 2 Prepare Your Search Index
Your search.json should include fields like title, excerpt, tags, and URL for each page. Example entry:
{
"title": "How to Use Jekyll Collections",
"excerpt": "Learn to organize your content with Jekyll collections...",
"tags": ["jekyll", "collections"],
"url": "/jekyll-collections"
}
Step 3 Initialize Fuse
const options = {
keys: ['title', 'excerpt', 'tags'],
threshold: 0.3,
includeMatches: true,
minMatchCharLength: 2
};
let fuse;
fetch('/search.json')
.then(res => res.json())
.then(data => {
fuse = new Fuse(data, options);
});
Building Autocomplete UI
Create a search input box with a results dropdown container in your layout:
<input type="search" id="search-box" placeholder="Search articles..." autocomplete="off">
<div id="autocomplete-results" role="listbox"></div>
Listening to Input Events
const searchBox = document.getElementById('search-box');
const resultsContainer = document.getElementById('autocomplete-results');
searchBox.addEventListener('input', () => {
const query = searchBox.value.trim();
if(query.length < 2) {
resultsContainer.innerHTML = '';
return;
}
const results = fuse.search(query);
renderResults(results);
});
function renderResults(results) {
if(!results.length) {
resultsContainer.innerHTML = '<p>No results found</p>';
return;
}
resultsContainer.innerHTML = results.map(({ item, matches }) => {
// Highlight matched terms in title
let highlightedTitle = item.title;
if(matches) {
matches.forEach(match => {
if(match.key === 'title') {
match.indices.forEach(([start, end]) => {
const before = highlightedTitle.substring(0, start);
const matchText = highlightedTitle.substring(start, end + 1);
const after = highlightedTitle.substring(end + 1);
highlightedTitle = `${before}<mark>${matchText}</mark>${after}`;
});
}
});
}
return `
<a href="${item.url}" role="option" tabindex="0">${highlightedTitle}</a>
`;
}).join('');
}
Enhancing Accessibility and Keyboard Navigation
Support arrow keys and Enter key to navigate and select results:
let selectedIndex = -1;
searchBox.addEventListener('keydown', e => {
const options = resultsContainer.querySelectorAll('a');
if(e.key === 'ArrowDown') {
selectedIndex = (selectedIndex + 1) % options.length;
options[selectedIndex].focus();
e.preventDefault();
} else if(e.key === 'ArrowUp') {
selectedIndex = (selectedIndex - 1 + options.length) % options.length;
options[selectedIndex].focus();
e.preventDefault();
} else if(e.key === 'Enter' && selectedIndex > -1) {
options[selectedIndex].click();
e.preventDefault();
}
});
Instant Search Result Previews
Instead of navigating away immediately, you can fetch and show a brief preview snippet from the selected article, improving user confidence.
Approach
- Use AJAX to fetch the article snippet or excerpt
- Display it inline below the search result
- Allow users to click to go to full article
Performance Considerations
- Limit search index size for very large sites
- Debounce input to reduce redundant searches
- Use caching or localStorage for search data
- Lazy load Fuse.js or search index on demand
Conclusion
Enhancing your Jekyll knowledge base with advanced client-side search features provides users a seamless, fast, and pleasant way to discover content. Combined with previous articles on search indexing and offline caching, this approach creates a modern, user-friendly documentation site on GitHub Pages without backend dependencies.