Insert the Shopify Search Box on Your Jekyll Site Using Lunr.js
Last updated: November 28 2024
If your site is built on Jekyll and you’re using Shopify as your e-commerce platform, adding a powerful and efficient search box is a smart move, as it makes it easier for visitors to find the content they want. With Lunr.js, you can create an on-site search feature that operates directly in the browser without relying on external services.
In this guide, we’ll show you how to insert a search box using Shopify and Lunr.js, allowing you to streamline your site’s search functionality and provide a seamless experience for your audience.
How to insert the search box on your Jekyll site using lunr.js
What is Lunr.js?
Lunr.js could be an excellent choice for you if you want to build the search. However, first, what is Lunr.js?
Lunr.js is known as a small, full-text library for use in the browser. It indexes JSON documents and brings along a simple search interface for retrieving documents that can match text queries the most. The search usually works in the following steps:
- Get the search term sent as a GET parameter to
search.html
. search.html
then reads the GET parameter and searches through JSON containing the searchable content.search.html
shows a search result list.
To get started, we will generate /js/search.js
to hold our search JavaScript and get junr.js installed to /js/lunr.min.js.
How to insert the Shopify search box on your Jekyll site using lunr.js?
Step 1: Create search.html
In the first step, we need to generate /search.html. This file contains a search box, a placeholder for showing results, a JSON output of all the content we want to search on. All JavaScript libraries are also included:
---
layout: search
---
<form action="/search.html" method="get">
<label for="search-box">Search</label>
<input type="text" id="search-box" name="query">
<input type="submit" value="search">
</form>
<ul id="search-results"></ul>
<script>
window.store = {
{% for post in site.posts %}
"{{ post.url | slugify }}": {
"title": "{{ post.title | xml_escape }}",
"author": "{{ post.author | xml_escape }}",
"category": "{{ post.category | xml_escape }}",
"content": {{ post.content | strip_html | strip_newlines | jsonify }},
"url": "{{ post.url | xml_escape }}"
}
{% unless forloop.last %},{% endunless %}
{% endfor %}
};
</script>
<script src="/js/lunr.min.js"></script>
<script src="/js/search.js"></script>
Step 2: Write JavaScript
Move to the next step, to have /js/search.js
perform 3 tasks, we need to write the JavaScript. Those three tasks include:
- Get the search term
- Perform the search
- Display the results
We are going over the sections of code. Then, we will see the whole file at the end.
Step 3: Get the search term
It is not really easy for JavaScript to instantly read GET parameters so we need to add a getParameterByName
function to get things done. Please do not be worried if you don’t get how this function works, it is merely manipulating the query string to divide it into variables.
Now you are able to employ getParameterByName
to get the search term:
...
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (pair[0] === variable) {
return decodeURIComponent(pair[1].replace(/\+/g, '%20'));
}
}
}
var searchTerm = getQueryVariable('query');
...
Step 4: Perform the search
Just in case there is a search term, we need to set up and adjust lunr.js. This job involves telling Lunr about the fields that interest you and adding the search data from the JSON. You can perform the search once this is already set up:
...
if (searchTerm) {
document.getElementById('search-box').setAttribute("value", searchTerm);
// Initalize lunr with the fields it will be searching on. I've given title
// a boost of 10 to indicate matches on this field are more important.
var idx = lunr(function () {
this.field('id');
this.field('title', { boost: 10 });
this.field('author');
this.field('category');
this.field('content');
});
for (var key in window.store) { // Add the data to lunr
idx.add({
'id': key,
'title': window.store[key].title,
'author': window.store[key].author,
'category': window.store[key].category,
'content': window.store[key].content
});
var results = idx.search(searchTerm); // Get lunr to perform a search
displaySearchResults(results, window.store); // We'll write this in the next section
}
}
...
Step 5: Display the result
Now you are allowed to show the results in your list when already having them.
...
function displaySearchResults(results, store) {
var searchResults = document.getElementById('search-results');
if (results.length) { // Are there any results?
var appendString = '';
for (var i = 0; i < results.length; i++) { // Iterate over the results
var item = store[results[i].ref];
appendString += '<li><a href="' + item.url + '"><h3>' + item.title + '</h3></a>';
appendString += '<p>' + item.content.substring(0, 150) + '...</p></li>';
}
searchResults.innerHTML = appendString;
} else {
searchResults.innerHTML = '<li>No results found</li>';
}
}
...
When putting it all together, you will have a working search:
(function() {
function displaySearchResults(results, store) {
var searchResults = document.getElementById('search-results');
if (results.length) { // Are there any results?
var appendString = '';
for (var i = 0; i < results.length; i++) { // Iterate over the results
var item = store[results[i].ref];
appendString += '<li><a href="' + item.url + '"><h3>' + item.title + '</h3></a>';
appendString += '<p>' + item.content.substring(0, 150) + '...</p></li>';
}
searchResults.innerHTML = appendString;
} else {
searchResults.innerHTML = '<li>No results found</li>';
}
}
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (pair[0] === variable) {
return decodeURIComponent(pair[1].replace(/\+/g, '%20'));
}
}
}
var searchTerm = getQueryVariable('query');
if (searchTerm) {
document.getElementById('search-box').setAttribute("value", searchTerm);
// Initalize lunr with the fields it will be searching on. I've given title
// a boost of 10 to indicate matches on this field are more important.
var idx = lunr(function () {
this.field('id');
this.field('title', { boost: 10 });
this.field('author');
this.field('category');
this.field('content');
});
for (var key in window.store) { // Add the data to lunr
idx.add({
'id': key,
'title': window.store[key].title,
'author': window.store[key].author,
'category': window.store[key].category,
'content': window.store[key].content
});
var results = idx.search(searchTerm); // Get lunr to perform a search
displaySearchResults(results, window.store); // We'll write this in the next section
}
}
})();
Step 6: Search field
Now only by adding a form that submits to /search.html can you be able to insert a search box any places on your store site. You will need to prefix the action with `` when you are using a base url on GitHub pages.
...
<form action="/search.html" method="get">
<label for="search-box">Search</label>
<input type="text" id="search-box" name="query">
<input type="submit" value="search">
</form>
...
Bottom Line
By incorporating Lunr.js into your Shopify Jekyll site, you can greatly enhance your website's usability by offering a fast, responsive search experience. This step-by-step guide ensures that adding a search box is straightforward so you can help visitors easily navigate through your content, whether it's blog posts or product pages.