Guides / Building Search UI / Widgets

You’re reading the documentation for Vue InstantSearch v3. Read our migration guide to learn how to upgrade from v2 to v3. You can still find the documentation for version 1 on our community website.

Introduction

You can build your own components when the provided ones are not sufficient.

You are trying to create your own widget with Vue InstantSearch and that’s awesome 🎉. But that also means that you couldn’t find the widgets or built-in options you were looking for. We’d love to hear about your use case as our mission with our InstantSearch libraries is to provide the best out-of-the-box experience. Don’t hesitate to send us a quick message explaining what you were trying to achieve either using the form at the end of that page or directly by submitting a feature request

Existing connectors

In some cases, you might want to create a component which uses a piece of data not currently provided by any of the widgets. You also might want to make a custom component for having access to the data in different places than the template.

You can do this with the createWidgetMixin function exposed by Vue InstantSearch. It works together with the connectors from InstantSearch.js. To get started, let’s choose the connectMenu connector for this example.

1
2
3
4
5
6
7
8
9
10
<script>
import { createWidgetMixin } from 'vue-instantsearch';
import { connectMenu } from 'instantsearch.js/es/connectors';

export default {
  mixins: [
    createWidgetMixin({ connector: connectMenu })
  ],
};
</script>

Then, all information from that connector will be available to your template as well as your other Vue lifecycle methods (after created). All information will be available on this.state on your instance, and will be null initially (so make sure your code is safe by wrapping usage in the template for example in an v-if="state").

All connectors expect to be passed widget parameters. Since these change over the life cycle of a component, and are usually passed via props, the widget mixin expects a property widgetParams on the component’s instance. You can create it via a computed property, based on props:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default {
  // ...
  props: {
    attribute: {
      type: String,
      required: true,
    },
  },
  computed: {
    widgetParams() {
      return {
        attribute: this.attribute,
      };
    },
  },
};

Then we can make use of state here to for example filter over the items (note that this is also possible with transform-items prop on ais-menu):

1
2
3
4
5
6
7
8
9
10
11
export default {
  // ...
  computed: {
    // ...
    items() {
      // no if needed here if we v-if in the template
      // only labels of three character long allowed
      return this.state.items.filter(item => item.label.length === 3)
    },
  },
};

Then in our template, we can use this as expected:

1
2
3
4
5
6
7
<ul>
  <li v-for="item in items" :key="item.value">
    <button @click="state.refine(item.value)">
      {{ item.label }}
    </button>
  </li>
</ul>

Custom connectors

Finally, if you want to make your own connector, you can do that using a function with this signature:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const connector = (renderFn, unmountFn) => (widgetParams = {}) => ({
  init({ instantSearchInstance }) {
    renderFn(
      {
        /* anything you put here comes in this.state */
      },
      true
    );
  },

  render({ results, instantSearchInstance }) {
    renderFn(
      {
        /* anything you put here comes in this.state */
      },
      false
    );
  },

  dispose() {
    unmountFn();
  },
});

That will give you access to the lowest level of abstraction, including the Algolia Helper.

Did you find this page helpful?