Create a keyboard navigable site search with Nuxt/Content and Aloglia vue-instantsearch 
Tags: algolia, vue, nuxt, tutorial
Published: 2021-01-13 18:59:19

This is a continuation of [Getting started with NuxtJS / Content module](https://dev.to/armiedema/getting-started-with-nuxtjs-content-module-3l5o).

---

Let's get right down into it and add an Algolia search component to our Nuxt/VueJS documentation site project. 

## Install Algolia vue-instantsearch

{% youtube vU0d2mEI1lE %}

In the [package.json](https://github.com/cleavr/docs-template/blob/phase-5/package.json) file, let's add the `algoliasearch` and `vue-instantsearch` dependencies. 

And, since we're here, let's also add `nuxt-content-algolia` and `v-outside-click` as we'll also use these packages while crafting the search functionality. 

```javascript 
"dependencies": {
    ...
    "algoliasearch": "^4.8.3",
    "vue-instantsearch": "^3.4.3",
    "nuxt-content-algolia": "^0.2.0",
    "v-click-outside": "^3.1.2",
    "remove-markdown": "^0.3.0"
  },
```

Next, in the project's root directory, run the `yarn install` command to install the newly defined packages. 

We need to now make some updates to the [nuxt.config.js](https://github.com/cleavr/docs-template/blob/phase-5/nuxt.config.js) file. 

```javascript
plugins: [
    '~/plugins/vue-instantsearch'
  ],
build: {
    transpile: ['vue-instantsearch', 'instantsearch.js/es']
  },
nuxtContentAlgolia: {
    appId: process.env.ALGOLIA_APP_ID,
    apiKey: process.env.ALGOLIA_API_KEY,
    paths: [
      {
        name: 'documentation',
        index: 'docs',
        fields: ['title', 'description', 'bodyPlainText']
      }
    ]
  },
hooks: {
    'content:file:beforeInsert': (document) => {
      const removeMd = require('remove-markdown');
      if (document.extension === '.md') {
        document.bodyPlainText = removeMd(document.text);
      }
    },
  },

```
We added quite a few new items to the Nuxt config file, so let's go through what they are. 

**plugins/vue-instantsearch** is Algolia's library of pre-built Vue components that we will leverage. 

**transpile** is needed in order for the Vue/Nuxt to understand the javascript version that Algolia uses. Make sure you define this, as you'll get a bunch of console errors otherwise!

**nuxtContentAlgolia** is a plugin that will index the defined `contents` folders and send corresponding tag data to Algolia during `yarn generate` - which is the command that will run when the site it build for static production hosting. 

{% youtube mmZ0CPZphXA %}

**hooks** have been added to send the markdown file plain body text with markdown characters stripped out to Algolia so that we can display body search results without any ugly html tags or markdown characters. 

Now, we'll add the [vue-instantsearch.js](https://github.com/cleavr/docs-template/blob/master/plugins/vue-instantsearch.js) file to the `plugins` directory. 

```javascript
import vue from 'vue';
import InstantSearch from 'vue-instantsearch'

vue.use(InstantSearch);
```

Alrighty, we now have our setup complete so we can start creating the search component! 

## Display search results

{% youtube tSCZqPRSQMI %}

In the [Search.vue](https://github.com/cleavr/docs-template/blob/master/components/Search.vue) file, we'll drop in vue-instantsearch components to handle search queries and display results. 

We'll first want to import the necessary module. 

```javascript
import algoliasearch from 'algoliasearch/lite';
```
Then, define `searchClient` and include the app id and search api id for our Algolia account. 

```javascript
data () {
    return {
      searchClient: algoliasearch('appID', 'searchApiID'),
    }
  },
```

Now, we can drop the vue-instantsearch components into the `<template>` section. 

Check out the [Search.vue](https://github.com/cleavr/docs-template/blob/master/components/Search.vue) file on GitHub and watch the above video to view the components that are being added and to learn what they do. There are quite a few and might be easier to view than read in this case. 😉

## Focus search box with 'command + k'

{% youtube UER5yCRveZU %}

Add a keyboard command to put the search box in focus is all the rage nowadays. 

Luckily, javascript is making it easier to detect and we don't have to worry about figuring out key values to refer to anymore. 🎉

On the search input field, we have a reference - `ref="searchInput"` that we will use to put into focus if certain keys are pressed. 

To define the keys, we'll need to add an event listener to pick up the events. Let's add this as a mounted function. 

```javascript
mounted: function () {
    this.$nextTick(function () {
      window.addEventListener('keydown', event => {
        if(event.metaKey && event.key === 'k') {
          this.$refs.searchInput.focus()
          event.preventDefault()
        }
      })
    })
  },
```
You may have noticed that we also want to prevent default actions. Some browser, ahem Firefox, will put the browser search into view if you press command + k on your keyboard. 

You'll also notice the `metaKey`. This is either the command key if you are using a Mac device or the windows key if you're using a Windows device. 

We can even detect what device type a user is using and define placeholder text based on that. 

```javascript
computed: {
    searchPlaceholder () {
      if (navigator.appVersion.indexOf('Mac') !== -1 ) {
        return 'Search - ⌘k to focus'
      }
      else if (navigator.appVersion.indexOf('Win') !== -1 ) {
        return 'Search - Win + k to focus'
      } else {
        return 'Search'
      }
    }
  },
```

## Close search results on outside click

{% youtube lZ2GykUl9EE %}

We installed a package earlier to help us detect outside clicks. 

Let's use that to close the search results dropdown when clicked outside of the search area. 

First, we'll import the package to the search.vue file. 

```javascript
import vClickOutside from 'v-click-outside'
```
And then, add it as a directive. 

```javascript
export default {
  directives: {
    ClickOutside: vClickOutside.directive
  },
}
```
We'll add this to the `ais-autocomplete` component and then refer to a method on outside click events. 

```html
<ais-autocomplete v-click-outside="onClickOutside">
```
We have a data item labeled `showResults` which is tied to `v-show` on the search results dropdown. This will determine if the results display or not. On an outside click, we want to set this to false. 

```javascript
methods: {
    onClickOutside () {
      this.showResults = false
    },
}
```

## Add keyboard commands to move through results and to go to result page on click of enter key

{% youtube Pqwdqp-oBsA %}

Let's add some more delights for our keyboard-first users. 

We'll add some more click handlers on the `<input>` tag. 

```html
<input
            ...
            @keydown.up.prevent="highlightPrevious"
            @keydown.down.prevent="highlightNext(indices[0].hits.length)"
            @keydown.enter="goToDoc(indices)"
          >
```

We also want to add a highlight effect if a user clicks the up/down arrows as well as if the user hovers over a search result. 

Let's add `:class="{ 'bg-blue-900' : isCurrentIndex(index) }"` to `<nuxt-link>` tag that highlights the current selected index. 

And, add `@mouseover="highlightedIndex = index"` to the child div of `<nuxt-link>`, which will handle the mouse over and change index based on the index of the result that is currently being moused over. 

Lastly, the we'll add the logic in the form of new methods to the `<script>` section. 

```javascript
highlightPrevious () {
      if (this.highlightedIndex > 0 ){
        this.highlightedIndex -= 1
      }
    },
    highlightNext (resultsCount) {
      if (this.highlightedIndex < resultsCount - 1) {
        this.highlightedIndex += 1
      }
    },
    isCurrentIndex (index) {
      return index === this.highlightedIndex
    },
    goToDoc (indices) {
      this.$nuxt.$router.push(indices[0].hits[this.highlightedIndex].objectID)
    }
```

You now have a fully functional site documentation search using Algolia and VueJS! 🔥

---
Following along? View the [GitHub Repo](https://github.com/cleavr/docs-template) to view the code for this tutorial. 

You can also view the full video [tutorial series playlist](https://youtube.com/playlist?list=PLApnZzwJN4G5jU3NzBPWpHWJiXTEO9esd) on YouTube. 

Looking for a tool to manage your VPS servers and app deployments? Check us out at [cleavr.io](https://cleavr.io)

--- 
Full tutorial series on creating a documentation site using Vue/Nuxt, Tailwind, and Algolia. 

{% link https://dev.to/armiedema/getting-started-with-nuxtjs-content-module-3l5o %}

{% link https://dev.to/armiedema/make-a-mobile-menu-display-and-hide-with-nuxt-vue-54mc %}

{% link https://dev.to/armiedema/pull-in-markdown-to-vue-with-nuxt-content-and-style-with-tailwind-typography-2em6 %}

{% link https://dev.to/armiedema/responsive-youtube-embeds-with-tailwindcss-4635 %}

{% link https://dev.to/armiedema/create-a-keyboard-navigable-site-search-with-nuxt-content-and-aloglia-vue-instantsearch-2d6o %}