How to add search functionality to a static web site

Hugo a static web site generator and lunr.js

Since version 0.20 Hugo has a build in capability to create a (customized) index file of available markdown documents down below the content directory tree.

Once this index file is available, we can use lunr.js - a jquery based javascript - to implement a search functionality. The search result pops up instantly, while the user is typing… - pretty neat!

What follows is a brief description to get the whole thing up and running.

Configuration setting (config.toml)

  • Make sure, to have the most recent hugo version installed, at least V0.20 is required. You might want to run: hugo version just to be sure.

  • Add the following to your config.toml configuration file:

    [outputs]
    home = [ "HTML", "RSS", "JSON"]
    
    
  • Note: Make sure to locate the required index.json file in the layouts folder. Once the file exists, hugo is going to dump the index to file.

    The index.json file looks like:

    [{{ range $index, $page := .Site.RegularPages }}
    {{- if ne $page.Type "json" -}}
    {{- if and $index (gt $index 0) -}},{{- end }}
    {
    	"__comments": "// hugo interface has changed since hugo v0.59: old: .Site.Pages new: .Site.RegularPages",
    	"uri": "{{ $page.Permalink }}",
    	"title": "{{ htmlEscape $page.Title}}",
    	"tags": [{{ range $tindex, $tag := $page.Params.tags }}{{ if $tindex }}, {{ end }}"{{ $tag| htmlEscape }}"{{ end }}],
    	"description": "{{ htmlEscape .Description}}",
    	"content": {{$page.Plain | jsonify}}
    }
    {{- end -}}
    {{- end -}}]
    
    

Once this is done, hugo generates a lunrjs index.json at the root of your public folder. If you encounter some problems run: hugo --verbose and check messages and warnings.

Web site configuration:

  • ../layouts/partials/header.html

    Typically, that’s where the css files are:

    <head>
    ...
    {{ if not .Site.Params.disableSearch }}
    	<link href="{{ .Site.BaseURL }}css/auto-complete.css" rel="stylesheet">
    {{ end }}
    ...
    </head>
    
  • ../layouts/partials/scripts.html

    Please note: as lunr.js is based on jquery, make sure jquery.js gets loaded 1st.

    <body>
    ...
    <!-- custom search -->
    {{ if not .Site.Params.disableSearch }}
    	<script type="text/javascript" src="{{ .Site.BaseURL }}js/lunr.min.js"></script>
    	<script type="text/javascript" src="{{ .Site.BaseURL }}js/auto-complete.js"></script>
    
    	<script type="text/javascript">
    		var baseurl = "{{ .Site.BaseURL }}";
    	</script>
    	<script type="text/javascript" src="{{ .Site.BaseURL }}js/search.js"></script>
    {{ end }}
    ...
     </body>
    
  • and finally, add a search entry box somewhere in your webpage layout:

    
    {{ if not .Site.Params.disableSearch }}
    	<li class="dropdown">
    	<a>
    		<i class="fa fa-search"></i>
    		<div class="searchbox pull-right">
    		<input data-search-input id="search-by" type="text">
    		</div>
    	</a>
    	</li>
    {{ end }}
    

That’s it.