You can contact me if you wish to comment or propose a correction.
Posted: 2024-06-04
Stats: 425 words / ~2 minutes
Introduction
In this tutorial I’ll show you how you can add a client-side-search page to your Hugo website.
This is done using Javascript and depends on fuse.js.
This tutorial is split in 5 parts:
- Copying fuse.js dependencies
- Configuring search layout
- Adding search page
- Editing hugo.yml
- Editing index.json
How it works
The search is processed by fuse.js. You can read more here more about the fuse.js Scoring theory or the API reference.
Getting started
Copying some fuse.js dependencies
First, you need to copy the fuse.js library:
wget https://cdn.jsdelivr.net/npm/fuse.js/dist/fuse.js
Copy it to static/js/search/fuse.js
.
Configuring search layout
Next, we need to add a search layout. Paste the following to layouts/_default/search.html
:
{{ define "main" }}
<body>
<noscript>
<div style="color: red;">Please enable JavaScript to use the search functionality.</div>
</noscript>
<div id="loading" style="display: block;">Loading...</div>
<div id="search-container" style="display: none;">
<input type="text" id="search-input" placeholder="Search...">
<ul id="search-results"></ul>
</div>
<script src="/js/search/fuse.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const loadingElement = document.getElementById('loading');
const searchContainer = document.getElementById('search-container');
const searchInput = document.getElementById('search-input');
const searchResults = document.getElementById('search-results');
fetch('/index.json')
.then(response => response.json())
.then(data => {
loadingElement.style.display = 'none'; // Hide loading indicator
searchContainer.style.display = 'block'; // Show search container
const options = {
keys: ['title', 'tags', 'categories', 'contents']
};
const fuse = new Fuse(data, options);
const performSearch = () => {
const query = searchInput.value;
const results = fuse.search(query);
searchResults.innerHTML = '';
results.forEach(result => {
const item = result.item;
const li = document.createElement('li');
const a = document.createElement('a');
a.href = item.permalink;
a.textContent = item.title;
li.appendChild(a);
searchResults.appendChild(li);
});
};
searchInput.addEventListener('input', performSearch);
// Perform initial search if there's already a value in the search input
if (searchInput.value) {
performSearch();
}
})
.catch(error => {
loadingElement.style.display = 'none'; // Hide loading indicator
console.error('Error loading index.json:', error);
});
});
</script>
</body>
{{ end }}
Adding search page
The last thing is to add a page. Just create a file named site.md
in your contents/
directory. Paste the following content:
---
title: "Search"
layout: "search"
---
Editing hugo.yml
You need to tell Hugo that a index.json page should be generated. This is used by the script for the search results:
outputs:
home:
- html
- json
Add the json
line.
Editing index.json
Hugo needs a template for creating the JSON.
Create a file called index.json
in the layouts/_default
directory.
Paste the following content:
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}
{{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}
End
You’re done! Test the search, and let me know if something doesn’t work.
This is my 14th post at 100DaysToOffload challenge