Seek, and Ye Shall Find

Photo by Emiliano Vittoriosi on Unsplash
Until this week, this site had no search. To find an old post, you paged through the Notes and hoped. That is fine for ten posts. There are more than seventy now.
So now there is a magnifying glass in the menu.
No server
I did not want a search server. This site is a set of static files on Cloudflare. A search server is one more thing to maintain, and a search service from a third party sees what my readers type. I did not want either.
Pagefind is an open-source tool from CloudCannon, and it works differently. It runs once, when I publish. It reads every page and writes an index, which is a folder of small files beside the site. When you search, your browser downloads only the parts of the index that your words need. Then your browser does the search.
The search engine is about 157 KB, and your browser downloads it once. Each search adds 30 to 80 KB. Indexing the whole site takes about 0.2 seconds.
What the index ignores
Every page has a menu and a footer. If Pagefind indexes them, every page matches the word “Donate”. So Pagefind ignores them.
Photo credits were the next problem. Each result shows a short extract from the page. On posts with a header photo, the extract was often “Photo by … on Unsplash”. True, but not useful. Pagefind ignores the credits now too.
The word that matched everything
I tested the search on my staging server. Then I typed “insane”. I got 111 results, which is every page in the index.
This is why. When Pagefind cannot find a word, it does not stop. It finds the longest indexed word that is the start of your word. “Insane” starts with “in”, and every page on this site contains “in”.
This is not carelessness. It is this behaviour that lets you search as you type: “spar” finds Sparkle before you finish the word. But it needs a limit, and other people have seen the same problem.
We found a way around it. Pagefind does not use the fallback for a word in quotation marks, but it still finds other forms of that word. So “building” in quotes still finds “build”. The search box now asks two questions about each word:
- Does the word in quotes find any pages?
- If not, do the words that Pagefind highlights start with what you typed? This keeps search as you type.
If both answers are no, Pagefind guessed. The box then shows “No results”, which is the correct answer. Now “insane” finds nothing, “spar” finds 45 pages and “building” finds 91.
One oddity stays. Search for “apps”, and the first result is Fine, Apple. You Win. Pagefind extends “app” to “apple”. That is the same feature that makes “spar” work, so it stays. I suspect Apple would approve of the ranking.
Our own search box
Pagefind includes a ready-made search box, but it cannot filter results. So we wrote a small one, 83 lines of JavaScript, on Pagefind’s API. It shows results as you type. It puts your search in the address field, so you can send a link to a search or bookmark one. It tells screen readers how many results there are.
command-K
I wanted a keyboard trigger. Claude first suggested the / key, as many sites use. But a shortcut that is one character fails WCAG 2.1.4. A person who controls the computer by voice could say a word that contains that character, and the search engine would activate. Unexpected behaviours like that are unforgivable.
So I chose commandK on a Mac and controlK on other computers. It opens the search page from any page. On the search page, it selects the search box. On a Mac, controlK does nothing new, because in a text field it deletes to the end of the line, and some people use that every day.
Try it. Press commandK and search for something. You never know what you might discover in the depths of this website.