Using PageFind with Eleventy for Search


In the past, I have implemented my own search for static sites and while it's good enough, it's not great. Recently Tweetback, a self-hosted Twitter archive, added search using PageFind so I dug into the code to see how it's done. PageFind is:

a fully static search library that aims to perform well on large sites, while using as little of your users’ bandwidth as possible, and without hosting any infrastructure

I hadn't even heard of PageFind until a few weeks ago so most of what I've learnt here came from the PageFind docs and the pull request that added search to Tweetback so a big thanks to Alistair for writing the PR.


Note: I had to change some directories for the demo to get this to work on GitHub pages but everything works exactly the same as below.

To get started, install the package to your Eleventy project. PageFind has more detailed installation instructions on their website here.

npm install --save-dev pagefind

Build the index

PageFind works by scanning a bunch of HTML files and looking for one of the data-pagefind attributes. We'll add the data-pagefind-body attribute to the article element that wraps the posts to tell it to index the post content:

<article data-pagefind-body>
{{ content | safe }}

We want to run the PageFind CLI after the site has been built so we use the after Eleventy event and run the command with execSync on all HTML files in the built site:

const { execSync } = require('child_process')

module.exports = function(eleventyConfig) {
eleventyConfig.on('eleventy.after', () => {
execSync(`npx pagefind --source _site --glob \"**/*.html\"`, { encoding: 'utf-8' })

Note: if you haven’t already, you must install child_process: npm i child_process. Once you have done that, add the line const execSync = require('child_process').execSync; somewhere before the function, in your .eleventy.js.

Update 24/07/23: If you have a lot (read: ~3000) of pages like I do then you might find the build crashes trying to build the index. If that's the case, do the pagefind command after your Eleventy site build script has finished instead of in the after event.

Note the _site source option - if your site is built to a different directory then change this. This outputs a _pagefind directory to the build folder.

Add a Search Box

PageFind has an API if you want to make your own search interface but for this we'll use the built-in UI. Add the following to wherever you want the search box to appear, in the case of this demo it's going on the home page.

Add the PageFind stylesheet either in the head or above your search box element. The additional styles are optional and only needed if you need a dark theme/mode.

<link href="/_pagefind/pagefind-ui.css" rel="stylesheet">

@media (prefers-color-scheme: dark) {
:root {
--pagefind-ui-primary: #eeeeee;
--pagefind-ui-text: #eeeeee;
--pagefind-ui-background: #152028;
--pagefind-ui-border: #152028;
--pagefind-ui-tag: #152028;

PageFind requires an element with an ID which can then be passed to the script.

<div id="search" class="search"></div>

<script src="/_pagefind/pagefind-ui.js" onload="new PagefindUI({ element: '#search', showImages: false });"></script>

Run your Eleventy serve script and if everything has worked, you should have a functioning search that searches all your posts:

Search box with McFly as the search term and three results The code for this is on GitHub and there is a live demo here.