Search code examples
vue.jsalgoliavue-instant-search

Algolia & Vue InstantSearch: Customising widgets with slot


I am trying to modify the output of an InstantSearch widget for Vue.

In the documentation (https://www.algolia.com/doc/api-reference/widgets/hits/vue/#customize-the-ui) it says that using the scope-slot it will override the complete DOM output of the widget:

enter image description here

But it does not seem to be the case here. This is my code below using slot with a simple <tr> and <td> elements:

enter image description here

Instead of rendering a <tr> with <td> inside of it, I see here:

  • A div with a class of ais-Hits
  • A nested ol with a class of ais-Hits-list
  • A nested li with a class of ais-Hits-item

enter image description here

The output is this:

enter image description here

If I go to inspect element and I delete the elements I mentioned above (see how div, ol and li are deleted):

enter image description here

Then the result is correct:

enter image description here

Am I doing something wrong? Shouldn't slot override the DOM output and leave the rest to the developer to style?

Any help would be much appreciated!


Solution

  • You have to use the default slots rather than item. You'll have full control over the render.

    <ais-hits>
      <ol slot-scope="{ items }">
        <li v-for="item in items" :key="item.objectID">
          <ais-highlight :hit="item" attribute="name" />
          <p>
            <ais-highlight :hit="item" attribute="description" />
          </p>
        </li>
      </ol>
    </ais-hits>
    

    Here is an example on CodeSandbox.


    The ais-Hits will always wrap the default slot with a div (see GitHub for the explaination). The only alternative to avoid this issue is to create your own widget with the mixin createWidgetMixin:

    <template>
      <ol v-if="state">
        <li v-for="item in state.hits" :key="item.objectID">
          <ais-highlight :hit="item" attribute="name" />
          <p>
            <ais-highlight :hit="item" attribute="description" />
          </p>
        </li>
      </ol>
    </template>
    
    <script>
    import { createWidgetMixin } from "vue-instantsearch";
    import { connectHits } from "instantsearch.js/es/connectors";
    
    export default {
      mixins: [createWidgetMixin({ connector: connectHits })]
    };
    </script>
    

    Here is an example on CodeSandbox.