January 7, 2022 jekyll search ☕️ buy me a coffee
Note: The jekyll-algolia
plugin has been deprecated and as such, I have decided to stop supporting the search bar for this blog. The code that was used previously to show a demo search bar can be found at the end of the post.
I got bored today and decided I needed a tool to let readers search my 29 blog posts. Writing my own backend API and such was too tedious so I got inspiration from the Bootstrap docs and decided to look into Algolia. Luckily for me, the kind folks at Algolia have already created Jekyll tool and autocomplete.js for me to use!
In this post I will talk you through my installation and implementation of Algolia.
The very first step is to add jekyll-algolia
to your Gemfile like so
and run bundle install
. The next, configure the plugin to work with the Algolia API1 in order to index your posts. This is what makes your blog searchable. For this you have to provide your account credentials. Luckily for you there is a free community tier!
You can find your credentials at algolia.com/account/api-keys/ and place them into your _config.yml
.
Another (optional) step is to exclude some files. The default behaviour is to index all markdown and html files. I chose to exclude a few by adding files_to_exclude: ['blog.html', 'atom.html', 'index.html', '404.html']
to the algolia
section of my config.yml
. This allows me to only provide search in the blog posts on my website.
The next, and final step in the backend set-up, is to run ALGOLIA_API_KEY='admin_api_key' bundle exec jekyll algolia
.
Running a single command every time there is a change to my blog is tedious and involves effort. So, as a good developer, I automatically want to automate as much as possible. Luckily, I’ve already set up a CD workflow on Github which makes this very easy for me. If you would like to do something similar, checkout my configuration file here
To implement the auto-indexing, I add
to the end of my Deploy
job, to ensure that the index is uploaded once everything is properly deployed.
Indexes are uploaded, the website is updated. Now the only thing that remains is implementing a functional search box… yikes. autocomplete.js
is to the rescue!
We’ll use the jsDeliver CDN to install Autocomplete along with the classic theme:
Next, initialize the library, with your Angolia account PUBLIC API KEY where ever makes sense. That location is header.html
for me since my search box is/will be there.
Next we must import Autocomplete with const { autocomplete, getAlgoliaResults } = window['@algolia/autocomplete-js'];
.
Now we’re ready to add the search box. Add a div with an id to your html, like <div id='autcomplete'></div>
. This is where the search bar will be.
Back in your <script>
, we add the bellow code:
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
autocomplete({
container: '#autocomplete',
placeholder: 'Search for posts',
getSources({ query }) {
return [
{
sourceId: 'posts',
getItems() {
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: '',
query,
params: {
hitsPerPage: 5,
snippetEllipsisText: '…',
},
},
],
});
},
templates: {
item({ item, createElement, components }) {
return createElement('div', null,
createElement('a', { href: item.url, class: "text-decoration-none text-body" },
components.Highlight({ hit: item, attribute: 'title', tagName: 'strong' })
),
);
},
noResults(){
return 'No Results';
}
},
},
]
}
});
It may seem daunting at first, but the API is quite intuitive upon closer inspection. getItem
gets the items, templates
provides templates for how to return results, noResults
is what shows when there are no results. The documentation for Autocomplete is surprisingly good so do check it out, as anything I write here pales in comparison to their efforts.
Algolia has built a very excellent set of tools for us casuals to play around with. There is no surprise why I’m seeing the “powered by Algolia” tag left, right and centre. I tried getting on the DocSearch program but was sadly rejected as they are prioritizing technical documentation websites first (see Bootstrap).
At the time of writing this post, I have 3 published blog posts so it works very well 100% of the time as all posts are being shown. It wil be interesting to see how my setup scales over time.
If you have any comments, questions, or queries, then please use the comment section below!
Added on 30/12/2023
Full code that used to display an example search bar at the top of this post.
<!-- autocomplete.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/algoliasearch-lite.umd.js" integrity="sha256-EXPXz4W6pQgfYY3yTpnDa3OH8/EPn16ciVsPQ/ypsjk=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-js"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-theme-classic"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/themes/reset-min.css" integrity="sha256-t2ATOGCtAIZNnzER679jwcFcKYfLlw01gli6F6oszk8=" crossorigin="anonymous">
<div id="autocomplete" class="nav-link"></div>
<script>
const searchClient = algoliasearch(
'',
'',
);
const { autocomplete, getAlgoliaResults } = window['@algolia/autocomplete-js'];
autocomplete({
container: '#autocomplete',
placeholder: 'Search for posts',
openOnFocus: true,
getSources({ query }) {
return [
{
sourceId: 'posts',
getItems() {
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: '',
query,
params: {
hitsPerPage: 5,
snippetEllipsisText: '…',
},
},
],
});
},
//
templates: {
item({ item, createElement, components }) {
return createElement('a', { href: item.url, class: "text-decoration-none text-body" }, createElement('div', null,
components.Highlight({ hit: item, attribute: 'title', tagName: 'strong' })
),
);
},
noResults(){
return 'No Results';
}
},
//
},
]}
});
</script>