How to make a client-side search engine with Vue.js and Lunr.js

Posted on January 29, 2019 in
4 min read

This is a little tutorial about making a search/filter Vue.js component using the powerful Lunr.js library.

A little disclaimer: I've purposely avoided any CSS styles also keeping minimal the HTML markup, using Vue without the CLI, to focus only on the logic and integration part for simplicity. I thought Vue.js learners may find this way useful.

A little Vue.js app

Suppose to have a little component that loads a JSON file and creates a items list based on a given array, such as:

Vue.component('mylist', {
    <li v-for="item in list" :key="">{{}}</li>

Here the working example:

See the Pen vue lunr search 1 by Fabio Franchino (@abusedmedia) on CodePen.

Then, we want to integrate a search/filter capability with an input text field:

Vue.component('mysearchbtn', {
    <input type="text" placeholder="type to search"
      @input="$emit('update:search', $" />

and here the updated example:

See the Pen vue lunr search 2 by Fabio Franchino (@abusedmedia) on CodePen.

Now we need to make both the components working together, let's say, when I type into the text field, the list should update according to the search pattern.

Welcome Lunr.js

Instead of reinventing the wheel by implementing a search algorithm, I'm going to exploit Lunr, a very powerful and configurable library that make complex search pretty neat!

Just to give a taste, you can search using some well-known patterns such as:

  • using the wildcard, i.e. Pete* to find anything that begins with pete
  • searching in a specific field object, i.e. email:* to find in email field the string that ends with
  • using operators to include or exclude specific keywords, i.e. me +you -her
  • Lunr handles plurals and articles for us as well
  • bonus tip, each result item comes with a score based on search relevance as well as additional useful information related

Setting Lunr up

Lurn requires the creation of an index based on a given dataset, such as:

var searchIndex = lunr(function () {

  documents.forEach(doc => {

An important thing to consider about Lunr is the result array that is not a filtered version of the original dataset but a new and different array of objects containing specific search result properties, I guess both for performance reasons and to provide additional search information without manipulating the original array.

That means we need to find a way to filter the original array based on the produced Lunr array. This is the function I use; basically, I set a new array on every search keyword change including only the items present in the search result based on the reference field (the id in this case):

this.list = []
this.resuls.forEach(d => {
    this.original.forEach(p => {
        if(d.ref == this.list.push(p)

I'm still wondering whether that is the best way to update the list from a performance perspective in Vue.js, though.

Now, the final examples looks like this:

See the Pen vue lunr search 3 by Fabio Franchino (@abusedmedia) on CodePen.

Hope this might be helpful to someone. I made it to integrate the functionality on a little tool I'm working on, Presenta.

Have a nice day!