Home > Shopify Development > Insert the search box on your Jekyll site using lunr.js

How to insert the search box on your Jekyll site using lunr.js in Shopify

Sam Nguyen
Sam Updated: March 30, 2024

Share:

Drive 20-40% of your revenue with Avada
avada email marketing

In order for users to be able to find relevant content easily, you can actively add search to your store site. It is a relatively small site. Therefore, you are allowed to perform the search entirely client side. In case there were so many blog posts, customers may need to wait for a long time to search the post. Hence, a backend search could be a good choice.

However, please keep reading our instructional writing on How to insert the search box on your Jekyll site using lunr.js to know more deeply about this topic.

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:

  1. Get the search term sent as a GET parameter to search.html.
  2. search.html then reads the GET parameter and searches through JSON containing the searchable content.
  3. 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 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:

  1. Get the search term
  2. Perform the search
  3. 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');
...

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>
...

Conclusion

This solution is also approachable to your blog posts, you can do the same thing for data files, collections, or static files.


Sam Nguyen is the CEO and founder of Avada Commerce, an e-commerce solution provider headquartered in Singapore. He is an expert on the Shopify e-commerce platform for online stores and retail point-of-sale systems. Sam loves talking about e-commerce and he aims to help over a million online businesses grow and thrive.

Stay in the know

Get special offers on the latest news from AVADA.