Adding Algolia search to my 404 page
Tags: jamstack, beginners, javascript, webdev
Published: 2023-08-31 13:55:00

[My site](https://joebailey.xyz) is pretty small, so I don't really need search functionality, but the [Netlify Algolia plugin](https://www.netlify.com/integrations/algolia/) looked easy enough to use and a bit of fun.

Diving into the [docs](https://www.algolia.com/doc/), I got a bit overwhelmed. Algolia's breadth of capabilities is huge. They definitely seem like the go-to for fully customisable search on a Jamstack site. But all I wanted was a quick half an hour set up. I started reading a few articles and eventually figured out that Algolia offers two main products, instantsearch and autocomplete. Instantsearch is wildly extensible and has an array of UI components to create full search experiences. Autocomplete, on the other hand, adds a little search box like I've seen on so many sites.

I installed the Netlify plugin and kicked off a new build to get the crawler running automatically which indexed the content on my site. As I'm using Nuxt, all of the pages are pre-rendered so the crawler can parse the content. If you have an SPA, you'll need to tweak a config setting in your `netlify.toml` file to get the crawler to render the Javascript on the page.

```toml
[[plugins]]
package = "@algolia/netlify-plugin-crawler"
  [plugins.inputs]
  branches = ['main', 'develop', 'feat/add-algolia']
  disabled = true
  pathPrefix = "/blog"
  customDomain = "example.com"
  renderJavaScript = true
```

I then tried to install the `@algolia/algoliasearch-netlify-frontend` plugin, but the install is broken on Windows [because they're using a UNIX specific command in their postinstall script](https://github.com/algolia/algoliasearch-netlify/issues/855). I started off by including it from JSDelivr instead as per their [docs](https://www.algolia.com/doc/tools/crawler/netlify-plugin/quick-start/), but ran into some issues with not being able to use the head property on the Nuxt error layout.

I wrote a little load script wrapper in the mounted hook, but this felt a little slow, having to load resources from a 3rd party, all the extra DNS overhead that that brings, and what if jsDelivr went down (unlikely).

```javascript
mounted () {
    this.loadScript('https://cdn.jsdelivr.net/npm/@algolia/algoliasearch-netlify-frontend@1/dist/algoliasearchNetlify.js', () => {
      algoliasearchNetlify({
        // Options
      })
    })
  },
  methods: {
    loadScript (url, callback) {
      const script = document.createElement('script')
      script.src = url
      script.onload = callback
      document.head.appendChild(script)
    }
  }
```

What I really wanted was to be able to import an es module and bundle it with my code, like a normal Javascript package. I ended up enabling Typescript in my project, my first foray, copying Algolia's source files, and importing like so (much simpler).

```javascript
import algoliasearchNetlify from './AlgoliasearchNetlify'
```

You can [view the commit](https://github.com/joebailey26/joebaileyxyz/commit/019f19ba69ac57d39e5fc9e230a3c9a02292411a) that adds the [`@algolia/algoliasearch-netlify-frontend`](https://www.npmjs.com/package/@algolia/algoliasearch-netlify-frontend) package to my project. There's a bit of technical debt here in that I manually need to update files if Algolia update their package, but it also means I can customise it no-end if need be. I also now control the requirements of Algolias core packages like [`@algolia/autocomplete-js`](https://www.npmjs.com/package/@algolia/autocomplete-js) and [`@algolia/client-search`](https://www.npmjs.com/package/@algolia/client-search), so can keep things more up-to-date. I feel like it's a good compromise.

The [Netlify walkthrough](https://app.netlify.com/plugins/@algolia/netlify-plugin-crawler/install) gives you the following code snippet, but I found it really difficult to work out what all the env variables were and which page in the Algolia dashboard to go to to get the right variable. I worked out that the dashboard shows you different API keys depending on which application you had last visited. How I longed for Stripe's docs here which automatically fill in the code samples with your keys.

```javascript
algoliasearchNetlify({
    appId: '<YOUR_ALGOLIA_APP_ID>',
    apiKey: '<YOUR_ALGOLIA_API_KEY>',
    siteId: '<YOUR_NETLIFY_SITE_ID>',
    branch: '<YOUR_TARGET_GIT_BRANCH>',
    selector: 'div#search',
})
```

Now I had a working search! I wanted to style it a little though, which Algolia let you do through their [config options](https://www.algolia.com/doc/tools/crawler/netlify-plugin/front-end/#parameter-param-theme). Just place this code in the `algoliasearchNetlify` config options.

```javascript
theme: {
  mark: '#fff', // Color of the matching content
  background: '#23263b', // Background Color of the input and the panel
  selected: '#111432', // Background Color of the selected item
  text: '#d6d6e7', // Color of the title of the items
  colorSourceIcon: '#d6d6e7' // Color of the icon on the left of results
}
```

After plugging the values in, I realised I'd need to dynamically update them due to the dark theme toggle on my site. I experimented a little with watching a `darktheme` prop and trying to destroy and recreate the search container, but eventually dove into their source code and picked out the bits of CSS I needed to change. Here's a snippet of what I added:

```scss
#search .aa-Autocomplete, .aa-Panel, .aa-DetachedContainer {
  --height: 3rem;
  --height-icon: 1.5rem;
  --color-input-icon: var(--grey);
  --color-mark: var(--green);
  --color-background: white;
  --color-selected: #ECECEC;
  --color-text: var(--grey);
  --color-source-icon: var(--grey)
}
```

The way the autocomplete works is that when you start typing, a popup displays with the top results. You can configure how many to show, but I left it at the default which is 5. Annoyingly, whenever you click off the window, the popup disappears, so you can't inspect it with dev tools. I did some Googling and found that you could pass a debug option to `algoliasearchNetlify` which keeps the popup open. That let me make the final styling touches I needed.

```javascript
algoliasearchNetlify({
    appId: '<YOUR_ALGOLIA_APP_ID>',
    apiKey: '<YOUR_ALGOLIA_API_KEY>',
    siteId: '<YOUR_NETLIFY_SITE_ID>',
    branch: '<YOUR_TARGET_GIT_BRANCH>',
    selector: 'div#search',
    debug: true
})
```

Overall, it was a bit of a pain to add Algolia with the Netlify plugin, the whole integration feels rushed on their part. It's not quite plug and play for an SPA or SSG. I can imagine it works well if you just have HTML files though and don't mind a few extra 3rd party resources. If I were to need a comprehensive search functionality in the future, I'd definitely go with Algolia, but for smaller projects, I'll be looking for something less complex. [Take a look at the new search feature](https://joebailey.xyz/foobar).


![Search](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/badxk2qrmtf50q3z2ncg.png)