Jekyll is an excellent static site generator, but it lacks built-in search functionality. Lunr.js is a lightweight client-side search library that allows you to add fast, API-free search to your site.
This guide will walk you through each step, ensuring that by the end, your Jekyll site has a fully functional search feature powered by Lunr.js.
- Why Use Lunr.js?
- Step-by-Step Guide to Implement Lunr.js Search
- Alternative Search Methods
- In Closing
Why Use Lunr.js?
Lunr.js is an easy-to-implement search solution that works entirely on the client-side, meaning:
- No need for backend APIs or databases
- Fast performance with small-to-medium sites
- Works offline since it’s JavaScript-based
Lunr.js indexes your content in a JSON format and matches queries in real time.
Step-by-Step Guide to Implement Lunr.js Search
1. Generate a JSON Search Index
Lunr.js requires structured data for searching, so we first need to create a search.json file that stores all posts or pages in a searchable format.
1. Create json.html
In the _layouts directory, create a file named json.html and write the following code. This extracts each post’s metadata and content into a structured JSON format.
---
layout: null
---
[
{% for post in site.posts %}
{
"title": "{{ post.title }}",
"url": "{{ post.url }}",
"content": "{{ post.content | strip_html | truncatewords: 50 }}"
}
{% if forloop.last == false %},{% endif %}
{% endfor %}
]
This will create a JSON file containing:
- Title
- URL
- Content (truncated to improve search efficiency)
2. Modify _config.yml to generate search.json
Add the following line to _config.yml. This ensures Jekyll generates the search.json file during site builds.
defaults:
- scope:
path: ""
values:
layout: "json"
3. Create search.json Output Page
Inside your Jekyll project, create a new page named search.json and add the following line.
---
layout: json
permalink: /search.json
---
After rebuilding the site, search.json will be available at your-site.com/search.json.
Now your Jekyll site has structured data ready for Lunr.js.
2. Install and Configure Lunr.js
Let’s move on to setting up Lunr.js.
1. Include Lunr.js
In default.html (or layout file) include Lunr.js via unpkg CDN:
<script src="https://unpkg.com/lunr/lunr.js"></script>
2. Create search.js for Search Logic
Now we need to fetch search.json, index the data, and process user queries.
In the assets/js/ directory, create a file named search.js and write the following code.
async function fetchSearchData() {
const response = await fetch("/search.json");
const data = await response.json();
const idx = lunr(function () {
this.field('title'); // Index title
this.field('content'); // Index content
this.ref('url'); // Use URL as reference
data.forEach(doc => this.add(doc));
});
document.querySelector("#search-input").addEventListener("input", function () {
const results = idx.search(this.value);
displayResults(results, data);
});
}
function displayResults(results, data) {
const resultContainer = document.querySelector("#search-results");
resultContainer.innerHTML = "";
results.forEach(result => {
const item = data.find(doc => doc.url === result.ref);
resultContainer.innerHTML += `<li><a href="${item.url}">${item.title}</a></li>`;
});
}
fetchSearchData();
Your JavaScript script is ready to handle search queries.
3. Add a Search Box to Your Site
Modify your Jekyll HTML template to include a search box and results area.
1. Edit default.html (or layout file)
This sample code adds a search field, a list to display search results, and links to Lunr.js and search.js.
<input type="text" id="search-input" placeholder="Search..." />
<ul id="search-results"></ul>
Don’t forget to include search.js in HTML file, too.
<script src="{{ '/assets/js/search.js' | absolute_url }}" defer></script>
4. Customize the Search Results
Right now, search results display as basic links, but you can customize how results appear.
Improving Results Display
Modify displayResults() inside search.js to add a preview snippet of the content. It shows “No results found” if no matches found.
function displayResults(results, data) {
const resultContainer = document.querySelector("#search-results");
const searchInput = document.querySelector("#search-input").value.trim();
// Clear and hide search results if input is empty
if (searchInput === "") {
resultContainer.innerHTML = "";
return;
}
resultContainer.innerHTML = "";
if (results.length === 0) {
resultContainer.innerHTML = "<li>No results found</li>";
return;
}
results.forEach(result => {
const item = data.find(doc => doc.url === result.ref);
resultContainer.innerHTML += `
<li>
<a href="${item.url}">
<strong>${item.title}</strong>
</a>
<p>${item.content.substring(0, 100)}...</p>
</li>`;
});
}
5. Test and Optimize the Search Function
- Open your Jekyll site in a browser
- Type keywords in the search box
- Check if relevant results appear
- Improve search indexing by tweaking search.json structure
Your Jekyll site now has fully functional search powered by Lunr.js.
Alternative Search Methods
If Lunr.js doesn’t fit your needs, consider these options.
1. Netlify Functions (Server-Side Search)
- Handles large data sets dynamically
- Works well for content-heavy sites
- Requires serverless backend configuration
2. Google Custom Search Engine
- Uses Google’s powerful search engine
- Quick to set up
- Limited customization and includes ads
Each method has advantages so choose the best one for your site’s needs.
In Closing
Lunr.js is a fantastic lightweight solution for adding search to Jekyll sites. No backend required and simple to implement. It also has easy customization options.
Now that you have detailed steps, how does it feel working with Lunr.js for the first time? Excited to test it on your site? Let me know if you need any tweaks before publishing.