Algolia DevCon
Oct. 2–3 2024, virtual.
UI libraries / Vue InstantSearch / Widgets
Signature
<ais-refinement-list
  attribute="string"
  // Optional parameters
  operator="string"
  :limit="number"
  :show-more="boolean"
  :show-more-limit="number"
  :searchable="boolean"
  :searchable-placeholder="string"
  :sort-by="string[]|function"
  :transform-items="function"
  :class-names="object"
/>
Import
1
2
3
4
5
6
7
8
9
import { AisRefinementList } from 'vue-instantsearch';
// Use 'vue-instantsearch/vue3/es' for Vue 3

export default {
  components: {
    AisRefinementList
  },
  // ...
};

1. Follow additional steps in Optimize build size to ensure your code is correctly bundled.
2. This imports all the widgets, even the ones you don’t use. Read the Getting started guide for more information.

About this widget

The ais-refinement-list widget is one of the most common widget you can find in a search UI. With this widget, users can filter the dataset based on facets.

The widget only displays the most relevant facet values for the current search context. The sort option only affects the facets that are returned by the engine, not which facets are returned.

This widget also implements search for facet values, which is a mini search inside the values of the facets. This makes it easy to deal with uncommon facet values.

Requirements

The attribute provided to the widget must be in attributes for faceting, either on the dashboard or using the attributesForFaceting parameter with the API.

If you are using the searchable prop, you also need to make the attribute searchable using the dashboard or using the searchable modifier of attributesForFaceting with the API.

Disappearing facet values

With many facet values, the available options can change depending on the user’s query. The refinement widget displays the most common facet values for a given query.

A user’s chosen value can vanish if they alter the query. This occurs because only the most common facet values are displayed when there are many options. A previously selected value might not appear if it’s uncommon for the new query.

To also show less common values, adjust the maximum number of values with the configure widget. It doesn’t change how many items are shown: the limits you set with limit and show-more-limit still apply.

Examples

1
<ais-refinement-list attribute="brand" />

Props

attribute
type: string
Required

The name of the attribute in the records.

To avoid unexpected behavior, you can’t use the same attribute prop in a different type of widget.

1
<ais-refinement-list attribute="brand" />
operator
type: string ("or"|"and")
default: "or"
Optional

How to apply refinements.

  • "or": apply an OR between all selected values.
  • "and": apply an AND between all selected values.
1
2
3
4
<ais-refinement-list
  [...]
  operator="and"
/>
limit
type: number
default: 10
Optional

How many facet values to retrieve. When you enable the show-more feature, this is the number of facet values to display before clicking the “Show more” button.

1
2
3
4
<ais-refinement-list
  [...]
  :limit="5"
/>
show-more
type: boolean
default: false
Optional

Whether to display a button that expands the number of items.

1
2
3
4
<ais-refinement-list
  [...]
  show-more
/>
show-more-limit
type: number
default: 20
Optional

The maximum number of displayed items (only used when show-more is set to true).

1
2
3
4
<ais-refinement-list
  [...]
  :show-more-limit="15"
/>
searchable
type: boolean
default: false
Optional

Adds a search input to let users search for more facet values. To make this feature work, you need to make the attribute searchable using the dashboard) or using the searchable modifier of attributesForFaceting with the API.

In some situations, refined facet values might not be present in the data returned by Algolia.

1
2
3
4
<ais-refinement-list
  [...]
  searchable
/>
searchable-placeholder
type: string
default: "Search here…"
Optional

The value of the search input placeholder.

1
2
3
4
<ais-refinement-list
  [...]
  searchable-placeholder="Search our products"
/>
sort-by
type: string[]|function
default: Uses facetOrdering if set, ["isRefined","count:desc","name:asc"]

How to sort refinements. Must be one or more of the following strings:

  • "count" (same as "count:desc")
  • "count:asc"
  • "count:desc"
  • "name" (same as "name:asc")
  • "name:asc"
  • "name:desc"
  • "isRefined" (same as "isRefined:asc")
  • "isRefined:asc"
  • "isRefined:desc"

It’s also possible to give a function, which receives items two by two, like JavaScript’s Array.sort.

If facetOrdering is set for this facet in renderingContent, and no value for sortBy is passed to this widget, facetOrdering is used, and the default order as a fallback.

In some situations, refined facet values might not be present in the data returned by Algolia.

When using an array, take steps to avoid creating infinite loops. When you use an array as a prop, it causes the widget to re-register on every render, and this can sometimes cause these infinite loops.

1
2
3
4
<ais-refinement-list
  [...]
  :sort-by="['isRefined', 'name:asc']"
/>
transform-items
type: function
default: items => items
Optional

Receives the items and is called before displaying them. Should return a new array with the same shape as the original array. Useful for transforming, removing, or reordering items.

In addition, the full results data is available, which includes all regular response parameters, as well as parameters from the Algolia search helper (for example disjunctiveFacetsRefinements).

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
<template>
  <!-- ... -->
  <ais-refinement-list
    [...]
    :transform-items="transformItems"
  />
</template>

<script>
  export default {
    methods: {
      transformItems(items) {
        return items.map(item => ({
          ...item,
          label: item.label.toUpperCase(),
        }));
      },

      /* or, combined with results */
      transformItems(items, { results }) {
        return results.page === 0
          ? items.slice(0, 5)
          : items;
      },
    },
  };
</script>
class-names
type: object
default: {}
Optional

The CSS classes you can override:

  • .ais-RefinementList: the root element of the widget.
  • .ais-RefinementList--noRefinement: the root element of the widget with no refinement.
  • .ais-RefinementList-list: the list of all items.
  • .ais-RefinementList-item: the list item.
  • .ais-RefinementList-item--selected: the selected list item.
  • .ais-RefinementList-label: the label of each item.
  • .ais-RefinementList-labelText: the text of the label of each item.
  • .ais-RefinementList-checkbox : the checbox element.
  • .ais-RefinementList-count: the count of values for each item.
  • .ais-RefinementList-searchBox: the searchbox when the widget is searchable.
  • .ais-RefinementList-noResults: the element rendered when the search doesn’t have results.
  • .ais-RefinementList-showMore: the button used to display more categories.
  • .ais-RefinementList-showMore--disabled: the disabled button used to display more categories.
1
2
3
4
5
6
7
8
<ais-refinement-list
  [...]
  :class-names="{
    'ais-RefinementList': 'MyCustomRefinementList',
    'ais-RefinementList-item': 'MyCustomRefinementListItem',
    // ...
  }"
/>

Customize the UI

default

The slot to override the complete DOM output of the widget.

Note that when you implement this slot, none of the other slots will change the output, as the default slot surrounds them.

Scope

  • items: object[]: the values applicable to this widget.
  • isShowingMore: boolean: is show-more enabled?
  • isFromSearch: boolean: true if there are search results.
  • canRefine: boolean: can the refinement be applied?
  • canToggleShowMore: boolean: is show-more possible?
  • toggleShowMore: () => void: toggles the number of displayed values between limit and show-more-limit.
  • searchForItems: (value: string) => void: a function to search into the facet values.
  • refine: (value: string) => void: a function to select a refinement.
  • createURL: (value: string) => string: a function to return a link for this refinement.
  • sendEvent: (eventType: 'click', facetValue: string) => void: the function to send click events.
    • The view event is automatically sent when the facets are rendered.
    • The click event is automatically sent when refine is called.
    • You can learn more about the insights middleware.

Where each item is an object containing:

  • value: string: the value of the item.
  • label: string: the human-readable value of the item.
  • count: number: the number of matched results after a refinement is applied.
  • isRefined: boolean: indicates if the refinement is applied.
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
<ais-refinement-list
  attribute="brand"
  searchable
  show-more
>
  <template
    v-slot="{
      items,
      isShowingMore,
      isFromSearch,
      canToggleShowMore,
      refine,
      createURL,
      toggleShowMore,
      searchForItems,
      sendEvent,
    }"
  >
    <input @input="searchForItems($event.currentTarget.value)">
    <ul>
      <li v-if="isFromSearch && !items.length">No results.</li>
      <li v-for="item in items" :key="item.value">
        <a
          :href="createURL(item)"
          :style="{ fontWeight: item.isRefined ?  'bold' : '' }"
          @click.prevent="refine(item.value)"
        >
          <ais-highlight attribute="item" :hit="item"/>
          ({{ item.count.toLocaleString() }})
        </a>
      </li>
    </ul>
    <button
      @click="toggleShowMore"
      :disabled="!canToggleShowMore"
    >
      {{ !isShowingMore ? 'Show more' : 'Show less'}}
    </button>
  </template>
</ais-refinement-list>
item

The slot to override the DOM output of an item.

Scope

  • item: object: an item object.
  • refine: (Item.value) => void: a function to select a refinement.
  • createURL: (Item) => string: a function to return a link for this refinement.

Where an item is an object containing:

  • value: string: The value of the item.
  • label: string: the human-readable value of the item.
  • count: number: the number of results matched after a refinement is applied.
  • isRefined: boolean: indicates if the refinement is applied.
1
2
3
4
5
6
7
8
9
10
11
12
<ais-refinement-list attribute="brand">
  <template v-slot:item="{ item, refine, createURL }">
    <a
      :href="createURL(item.value)"
      :style="{ fontWeight: item.isRefined ? 'bold' : '' }"
      @click.prevent="refine(item.value)"
    >
      <ais-highlight attribute="item" :hit="item"/>
      ({{ item.count.toLocaleString() }})
    </a>
  </template>
</ais-refinement-list>
showMoreLabel

The slot to override the DOM output of the “Show more” button.

Scope

  • isShowingMore: boolean: is the list of items expanded?
1
2
3
4
5
<ais-refinement-list attribute="brand" show-more>
  <template v-slot:showMoreLabel="{ isShowingMore }">
    {{ !isShowingMore ? 'More' : 'Less' }}
  </template>
</ais-refinement-list>
noResults

The slot to override the DOM output of the no results placeholder.

Scope

  • query: string: the current value of the query.
1
2
3
4
5
<ais-refinement-list attribute="brand" searchable>
  <template v-slot:noResults="{ query }">No results for
    <q>{{ query }}</q>
  </template>
</ais-refinement-list>

HTML output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="ais-RefinementList">
  <div class="ais-RefinementList-searchBox">
    <!-- SearchBox widget here -->
  </div>
  <ul class="ais-RefinementList-list">
    <li class="ais-RefinementList-item ais-RefinementList-item--selected">
      <label class="ais-RefinementList-label">
        <input class="ais-RefinementList-checkbox" type="checkbox" value="Insignia™" checked />
        <span class="ais-RefinementList-labelText">Insignia™</span>
        <span class="ais-RefinementList-count">746</span>
      </label>
    </li>
    <li class="ais-RefinementList-item">
      <label class="ais-RefinementList-label">
        <input class="ais-RefinementList-checkbox" type="checkbox" value="Samsung">
        <span class="ais-RefinementList-labelText">Samsung</span>
        <span class="ais-RefinementList-count">633</span>
      </label>
    </li>
  </ul>
  <button class="ais-RefinementList-showMore">Show more</button>
</div>
Did you find this page helpful?