How to add search to your Jekyll website

how-to jekyll
Ram Patra Published on November 29, 2019
Image placeholder

Jekyll is a static website generator that takes your plain text files and converts them to a beautiful website/blog.

People mostly use markdown files to write content and then use Jekyll to convert these markdown (.md) files to Html pages. Now, as there are no database nor backend application servers, there are limited ways to add a search feature to such a website. To be more specific, we have the following options:

  1. Google Custom Search
  2. Algolia Search Widget
  3. Custom search with the help of Javascript (may use 3rd party js libraries too)

In this blog, we will discuss the 3rd option and if you want to know why I went with this option and not the other two you can another post which describes how I made my blog.

There are two main steps in this option:

First, we need to have a file that will have details of all our posts. This file will basically act as our database. The RSS xml file can be used but the RSS feed file generated by jekyll-feed plugin contains only the recent 10 posts. This number is hardcoded into the plugin and is not configurable. Therefore, we have two options here, first, fork jekyll-feed plugin which I’ve already done, second, we need to explicitly generate a file that would contain metadata about all the posts. As there are no backend servers nor databases, we would ideally do the search on the client-side, i.e, with the help of Javascript. Therefore, it would be prudent to generate a json file which would contain the details of all our posts. We can then use this json file in our javascript code to search. Sounds simple? Cool, let’s see how we can create the json file.

layout: null
{% for post in site.posts %}
        "title" : "{{ post.title }}",
        "url" : "{{ post.url }}",
        "date" : "{{ post.date | date: "%b %d, %Y" }}",
        "content" : "{{ post.content | strip | strip_html | strip_newlines | replace: '"', '' | slice: 0, 600 }}"
    }{% if forloop.last %}{% else %},{% endif %}
    {% endfor %}

File: site.json

Place the above file in the root directory of your project. This will create a json array with all the metadata which we can use in our search method. You can even see the site.json file of my website.

Second, implement the search method in Javascript. We basically add an event listener and once our required event is triggered we perform the search. This can be a button click event or a keyup event. I chose the latter because I wanted to refresh the results as the user types, just like how Google Search works.

var posts = []; // will hold the json array from your site.json file

$("body").on("click", "[data-action]", function (e) {

    var $this = $(this);
    var action = $this.data('action');
    var target = $this.data('target');
    if (action === 'omnisearch-open') {
        var $searchFormEl = $(target).find('.form-control');
        search($searchFormEl.val()); // to handle cases where the search field isn't empty, i.e, the user searched for something earlier
        $searchFormEl.keyup(function (e) { // refresh results while user is typing


function search(searchStr) {

function searchCallback(searchStr) {
    return function () {
        var options = { 		// initialize options for fuse.js
            shouldSort: true,
            threshold: 0.4,
            location: 0,
            distance: 100,
            maxPatternLength: 32,
            minMatchCharLength: 1,
            keys: [
                    name: "title",
                    weight: 0.3		// give title more importance
                    name: "content",
                    weight: 0.4

        // initialize fuse.js library
        var fuse = new Fuse(posts, options);
        var results = fuse.search(searchStr); // invoke search method in fuse.js library

        if (searchStr.length === 0) {
            updateResults(posts.slice(0, 5), true); // if there are no search results, show some suggestions
        } else {
            updateResults(results, false);

In the above code, if you see I’ve used fuse.js library to perform the search. You can simply do a string match in javascript and filter the results but what’s the fun in that, right. Therefore, I compared various client-side search libraries and even used lunr.js at first but later learned that it lacked the Edit distance algorithm which I think is important to be in a search library. The Edit distance algorithm basically takes care of typos and shows the closest results. So, I went with fuse.js and it wasn’t only because of that but fuse.js also has great documentation, is easier to use, does the job well, and last but not least, is the most trending on the market now.

It is simply two lines of code to use the fuse.js library. You initialize the library new Fuse(posts, options); and then invoke the search method fuse.search(searchStr);.

Below is the code to update the search results on the UI. This code snippet is taken from this website. You can see how it looks by hitting the search button at the top. Now, this will be different based on your design but I’ve shared it here so that you at least get an idea of what’s involved.

function updateResults(results, isSuggestion) {
	var resultsHtml = '';

    results.forEach(function (res) {
        resultsHtml += '<li>' +
            '<a class="list-link" href="' + res.url + '">' +
            '<i class="search-icon" data-feather="' + (isSuggestion ? 'clock' : 'search') + '"></i> ' +
            '<span>' + res.title + '</span><small> on ' + res.date + '</small>' +
            '</a>' +
    var resultsWrapperHtml = '<h6 class="heading">Search ' + (isSuggestion ? 'Suggestions' : 'Results') + '</h6>' +
        '<div class="row">' +
        '<div class="col-sm-12">' +
        '<ul class="list-unstyled mb-0">' + resultsHtml + '</ul></div></div>';
    // insert the result html into the page
    // render feather icons
    feather.replace({class: 'search-icon', width: '1em', height: '1em'});


Lastly, below is the code to load the site.json file and get the metadata into an array. If you’re wondering what are those $ signs everywhere are then please read about jQuery framework. This is the only dependency in my code which you can easily get rid of as I am not doing anything complex here.

function fetchSiteJson(callback) {
    if (posts.length === 0) {
    	// fetch site.json file
    	$.get("/site.json", function (data) {
    		posts = data;
    } else { // we already have the posts so simply use it instead of downloading the file again

The above code snippets are taken from this website. If you want to see a live demo of how everything looks and feels like then hit the search button at the top. For any queries, please feel free to drop a comment below. Cheers!

Ram Patra Published on November 29, 2019
Image placeholder

Keep reading

If you liked this article, you may like these as well

February 6, 2022 My latest PC Build in 2022

I wrote a post in the past describing my crypto mining plus gaming pc and after around 2-3 years of using it, I decided to add more GPUs to it and totally dedicate it to mining crypto. Ergo, I needed a new PC for my gaming and other day-to-day tasks apart from app development. App development I do only on my mac. In this post, I would be describing all the components I used in my PC and why I chose them over others.

pc-build windows pc-fan January 29, 2022 How to control the fan speed in Windows? (for example, Antec fans on a MSI Motherboard)

In this blog post, we are going to see how to control the fan speed/RPM of Antec Prism ARGB 120mm fans on a MSI X570 Tomahawk Motherboard. Having said that, the process should be similar for other fans and motherboards.

January 25, 2020 How to know whether a user is using an adblocker

Adblocker detection is a nice feature to have, given that around 47% of the users now use ad blockers according to GlobalWebIndex.