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:
1
| 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
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| {{ 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:
1
2
3
4
| ---
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:
1
2
3
4
| 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:
1
2
3
4
5
| {{- $.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.