Guides / Building Search UI / Widgets

Show and hide Vue InstantSearch widgets

Widgets do more than display a UI—they each interact with a piece of the UI state that maps to one or more Algolia search parameters.

For example, the ais-search-box controls the query, the ais-refinement-list interacts with facetFilters, parameter.

When a widget is mounted or unmounted, this is reflected in the InstantSearch UI state and included in search requests.

Consider what happens in a mobile search interface with filters (ais-refinement-list): when a user clicks the Filters button, a dialog opens and displays the refinements.

In many component libraries, the <Dialog> component mounts and unmounts its content when toggled. This is problematic when used with InstantSearch components.

For example, if you have a ais-refinement-list widget nested in the dialog:

  • The widget wouldn’t be mounted on the first app load because the dialog box is closed.
  • When the dialog box opens, the widget mounts, adding it to the InstantSearch state and triggering a new request, even before a refinement has been selected.
  • When the dialog box closes, the widget unmounts, removing it from the InstantSearch state and losing all selected refinements.

To keep the state available after unmount, you can either:

Enable preserveSharedStateOnUnmount

Enabling preserveSharedStateOnUnmount prevents a widget’s state from being cleared when it’s unmounted, as long as other widgets share the same refinements. Enabling this option changes how dispose is used in the InstantSearch lifecycle.

By default when a widget is removed, it provides a cleared version of the state that will be propagated throughout the other widgets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<template>
  <ais-instant-search
    :future="{ preserveSharedStateOnUnmount: true }"
    :search-client="searchClient"
    index-name="instant_search"
  >
    <Search />
    <button type="button" @click="showMenu != showMenu">Filters</button>
    <virtual-refinement-list attribute="brand" />
    <ais-refinement-list v-if="showMenu" attribute="brand" />
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch/lite';
import { connectRefinementList } from 'instantsearch.js/es/connectors';
import { AisInstantSearch, AisRefinementList, createWidgetMixin } from 'vue-instantsearch';

const searchClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey',
);

const VirtualRefinementList = {
  name: 'VirtualRefinementList',
  mixins: [createWidgetMixin({
    connector: connectRefinementList,
  })]
  render() {
    return null;
  }
}

export default {
  components: {
    AisInstantSearch,
    AisRefinementList,
    VirtualRefinementList,
  },
  data() {
    return {
      searchClient,
      showMenu: true,
    };
  },
};
</script>

This option is available from v4.11.0 and will be the only option from Vue InstantSearch v5.

Keep the widget mounted but hidden

The most straightforward way to retain a widget’s state and refinements is to avoid unmounting it.

You can, for example, hide the content of the dialog with CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
  <ais-instant-search
    :future="{ preserveSharedStateOnUnmount: true }"
    :search-client="searchClient"
    index-name="instant_search"
  >
    <Search />
    <button type="button" @click="showMenu != showMenu">Filters</button>
    <ais-refinement-list v-show="showMenu" attribute="brand" />
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch/lite';
import { AisInstantSearch, AisRefinementList } from 'vue-instantsearch';

const searchClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey',
);

export default {
  components: {
    AisInstantSearch,
    AisRefinementList,
  },
  data() {
    return {
      searchClient,
      showMenu: true,
    };
  },
};
</script>

If you’re using a component library, you can verify whether the dialog component lets you avoid unmounting its content. For example, the <Dialog> component from Headless UI lets you turn off unmounting with the unmount option.

Did you find this page helpful?