Creating a Search Bar component with Elasticlurn and MDX
Since I've recently moved from using markdownRemark to MDX on all my Gatsby Sites, the instructions to some plugins might not be that straightforward to follow. Recently, I've created a Digital Garden and wanted to add a search bar to it.
On one of my first Gatsby projects, I had used the Elasticlurn Plugin for Gatsby to add a search bar to a website. I decided to try and use this plugin since I don't have to use an external service like Algolia.
Installing and Configuration
Installing the plugin is pretty straightforward. You need to run the command:
shell1npm install @gatsby-contrib/gatsby-plugin-elasticlunr-search
Then on your gatsby-config.js file, you can add the configuration for the plugin. If you read the README.md, you can see that one of the configuration options is the resolvers, here you need to replace MarkdownRemark
for Mdx
.
javascript1{2 resolve: `@gatsby-contrib/gatsby-plugin-elasticlunr-search`,3 options: {4 fields: [`title`, `category`, `tags`, `excerpt` ],5 resolvers: {6 Mdx: {7 title: node => node.frontmatter.title,8 category: node => node.frontmatter.category,9 tags: node => node.frontmatter.tags,10 excerpt: node => node.frontmatter.excerpt,11 slug: node => node.fields.slug12 }13 },14 filter: (node, getNode) => node.frontmatter.category15 }16 }
My frontmatter contains all those fields (but the slug). These are the fields that I want users to be able to search. You can choose as many or as little as you want.
Search Bar Component
With the plugin installed and configured, we have to create the search bar component. I re-used the component that I had created on the other project.
Note: This component needs refactoring. Most of this code was taken from the plugin instructions.
javascript1import React, { Component } from "react"2import { Index } from "elasticlunr"3import { Link } from "gatsby"4
5export default class Search extends Component {6 constructor(props) {7 super(props)8 this.state = {9 query: ``,10 results: []11 }12 }13
14 render() {15 return ( 16 <div className="my-5 relative">17 <div className="flex justify-center items-center">18 <i className="gg-search mr-2" />19 <input type="text" value={this.state.query} onChange={this.search} placeholder="Search..." />20 </div>21 {this.state.results.length !== 0 ? 22 <div className="mt-2 flex flex-col absolute z-10 search-results">23 {this.state.results.map(page => (24 <Link className="link m-1" to={`${page.slug}`} key={page.title}>25 <span className="underline">{page.title}</span> : <span className="green">{page.tags.join(', ')}</span>26 </Link>27 28 ))}29 </div>30 : ''}31 </div>32 )33 }34
35 getOrCreateIndex = () =>36 this.index ? this.index : Index.load(this.props.searchIndex)37 38 search = evt => {39 const query = evt.target.value40 this.index = this.getOrCreateIndex()41 this.setState({42 query,43 results: this.index44 .search(query, { expand: true})45 .map(({ ref }) => this.index.documentStore.getDoc(ref))46 })47 }48}
I want users to get partial matches straight away. So when you type something, you will get all matches first. Then the query will return fewer results. If you don't want this to happen and return the search results instead, you can remove the { expand: true }
parameter from the search
method.
You can probably see that on this site I am using TailwindCss. The only bit of CSS that I added outside Tailwind was the search-results
which adds some styling(colour, spacing) to that div. The reason why I decided to use an absolute position, is because I want the search results to drop down and stay above the content.
Importing and Using the Search Bar
Now that the search bar component is completed, you can use it anywhere on your site by importing it. But you also need to provide a searchIndex
to the component. Luckily, the plugin adds a query for you to use.
graphql1query {2 siteSearchIndex {3 index4 }5}
Then you can import the search bar component and use it like this:
javascript1<SearchBar searchIndex={props.data.siteSearchIndex.index} />
That's all there is to add a search bar with elasticlunr plugin and MDX. If you have any issues feel free to reach me on Twitter @FabioRosado, I will be happy to give you a hand!
References: