Adding a search bar for Hugo with Pagefind

Yesterday I was contemplating the idea of adding a search bar to this blog. Alright, being honest, this is a tough decision. I really like the idea of my website weighting almost nothing, but I also believe that I should make it easier for people to search for what they are looking after, including myself.

I’ll write this as a fun exercise and documentation for the future me. At the end of it, I might have a search bar or not. 🤪

After some research, I decided to settle with Pagefind due to it’s “zero-config” nature. I really like almost zero-config software! Now, let the fun begin.

Filtering content and adding metadata

Skimming through the documentation, I found what is needed to only show my posts on “Limiting what sections of a page are indexed”. This means that I only need to put the attribute data-pagefind-body on my layouts/_default/single.html layout to have it ignore tags and other Hugo Taxonomies.

It’s also possible to add metadata do the pages can also add metadata with the data-pagefind-meta attribute:

<!-- layouts/_default/single.html -->

<!-- ... -->

{{ define "main" }}
  <article data-pagefind-body>
    <h1 data-pagefind-meta="title">{{ .Title }}</h1>
    <!-- ... -->
      datetime="{{ .Date.Format "2006-01-02" }}" pubdate>
        {{ .Date.Format "02 Jan 2006" }}
    <!-- ... -->
{{ end }}

One caveat that I found was that using the attribute data-pagefind-meta="title" would make the output look weird with a bunch of ampersands. This problem is being tracked on the GitHub Issue #459.

Adding the Pagefind UI component

Fortunately, Pagefind does provide a default UI component that is rather easy to use. You can find the JavaScript file for it on the output of the indexing command:

$ pagefind --site public --output-path=static/js/pagefind
# the file will at static/js/pagefind/pagefind-ui.js

One tip I can give is to gitignore the Pagefind output directory, you don’t need to commit it to your repository as you can always regenerate it. Now, at the end of my layouts/_default/list.html file I add the needed code to show the search bar.

<!-- layouts/_default/list.html -->

<!-- ... -->

<script src="/js/pagefind/pagefind-ui.js" type="text/javascript"></script>
  window.addEventListener('DOMContentLoaded', (event) => {
    new PagefindUI({
      baseUrl: "/",
      // search element id
      element: "#search",
      // do not show images
      showImages: false,
      // I want to use my own CSS
      resetStyles: true,
      // do not show subresults of the same page
      showSubResults: false,
<div id="search"></div>

Building your website

This whole setup does introduce some build complexities to the whole website. This is mostly caused by all the tools not having a common interface to talk to. I’m glad this whole website is orchestrated with a single Makefile1. Let’s try to solve this dependency puzzle with the help of our beloved GNU Make.

The first thing we need to build our index, is the public directory Hugo generates. After this, we can run the Pagefind CLI and then publish our website.

	pagefind --site public --output-path=static/js/pagefind
	# copies pagefind index to the public directory
	cp -r static/js public

publish: public
	echo "your publishing command"

run: public
	hugo server --buildDrafts --buildFuture

	rm -rf public
	rm -rf site.tar.gz
	rm -rf static/js/pagefind

.PHONY: clean run publish

This is a nice trick to use, run depending on public ensures that we also have the search bar on our development enviroment with hugo server.

  1. Which is absolutely not POSIX. 😁 ↩︎

Articles from blogs I follow around the net

The four tenets of SOA revisited

Twenty years after. In the January 2004 issue of MSDN Magazine you can find an article by Don Box titled A Guide to Developing and Running Connected Systems with Indigo. Buried within the (now dated) discussion of the technology…

via ploeh blog March 4, 2024

Building a demo of the Bleichenbacher RSA attack in Rust

Recently while reading Real-World Cryptography, I got nerd sniped1 by the mention of Bleichenbacher's attack on RSA. This is cool, how does it work? I had to understand, and to understand something, I usually have to build it. Well, friends, that is what…

via blog March 4, 2024

How to unbreak Dolphin on SteamOS after the QT6 update

A recent update to Dolphin made it switch to QT6. This makes it crash with this error or something like it: dolphin-emu: symbol lookup error: dolphin-emu: undefined symbol: _Zls6QDebugRK11QDockWidget, version Qt_6 This is fix…

via Xe Iaso's blog March 3, 2024

Generated by openring