> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create your widgets

> Learn how you can create a custom widget for your Vue InstantSearch app.

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">Vue</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/widgets/create-your-own-widgets/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/widgets/create-your-own-widgets/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/guides/building-search-ui/widgets/create-your-own-widgets/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/widgets/create-your-own-widgets/ios"><span className="afs-option-name">iOS</span><span className="afs-option-lib">InstantSearch iOS</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/widgets/create-your-own-widgets/android"><span className="afs-option-name">Android</span><span className="afs-option-lib">InstantSearch Android</span></a></li>
    </ul>
  </div>
</div>

You can build your own components when the provided ones aren't sufficient.

<Info>
  If you're creating a custom InstantSearch widget because you didn't find a built-in option for your use case,
  consider [opening a feature request](https://github.com/algolia/instantsearch/discussions/new?category=ideas\&labels=triage\&title=Feature%20request%3A%20) to describe what you're trying to build.
</Info>

## Existing connectors

Sometimes you might want to create a component which uses a piece of data not 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](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/js#customize-the-complete-ui-of-the-widgets) from InstantSearch.js.

<Steps>
  <Step title="Connect the menu widget">
    Choose the [`connectMenu`](/doc/api-reference/widgets/menu/js) connector for this example.

    <CodeGroup>
      ```vue Vue 3 theme={"system"}
      <script>
      import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
      import { connectMenu } from 'instantsearch.js/es/connectors';

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

      ```vue Vue 2 theme={"system"}
      <script>
      import { createWidgetMixin } from 'vue-instantsearch';
      import { connectMenu } from 'instantsearch.js/es/connectors';

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

    All information from that connector will then 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"`).
  </Step>

  <Step title="Determine widget parameters">
    All connectors expect to be passed widget parameters.
    Since these change over the lifecycle of a component, and are usually passed through props, the widget mixin expects a property `widgetParams` on the component's instance.
    Create it with a `computed` property, based on props:

    ```js Vue icon=code theme={"system"}
    export default {
      // ...
      props: {
        attribute: {
          type: String,
          required: true,
        },
      },
      computed: {
        widgetParams() {
          return {
            attribute: this.attribute,
          };
        },
      },
    };
    ```
  </Step>

  <Step title="Filter items by widget state">
    Use `state` here to filter over the items.

    ```js Vue icon=code theme={"system"}
    export default {
      // ...
      computed: {
        // ...
        items() {
          // Not needed here if you v-if in the template
          // Only labels of three character long allowed
          return this.state.items.filter(item => item.label.length === 3)
        },
      },
    };
    ```

    <Info>
      This is also possible with the `transform-items` prop on [`ais-menu`](/doc/api-reference/widgets/menu/vue)).
    </Info>

    For more information, see [UI state](/doc/api-reference/widgets/ui-state/vue).
  </Step>

  <Step title="Render menu items in the template">
    ```vue Vue theme={"system"}
    <ul>
      <li v-for="item in items" :key="item.value">
        <button @click="state.refine(item.value)">
          {{ item.label }}
        </button>
      </li>
    </ul>
    ```
  </Step>
</Steps>

## Custom connectors

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

```js JavaScript icon=code theme={"system"}
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 lets you access the lowest level of abstraction,
including the [Algolia search helper](/doc/guides/building-search-ui/upgrade-guides/js#algolia-search-helper).
