Skip to main content

Core concepts

Vue InstantSearch is built around three core concepts:

Widgets

Vue components that render search UI elements like search boxes, hits, and filters

Connectors

Logic layer that manages widget state and search parameters

InstantSearch instance

The root component that coordinates all widgets and manages the search state

The InstantSearch wrapper

Every Vue InstantSearch implementation requires the <ais-instant-search> component as the root wrapper. This component manages the search state and coordinates all child widgets.

Required props

Common props

Basic example

<template>
  <ais-instant-search
    :search-client="searchClient"
    index-name="products"
    :insights="true"
    :routing="routing"
  >
    <!-- Your search widgets go here -->
  </ais-instant-search>
</template>

<script>
import { liteClient as algoliasearch } from 'algoliasearch/lite';

export default {
  data() {
    return {
      searchClient: algoliasearch('YourAppID', 'YourSearchKey'),
      routing: {
        router: {
          // Custom router implementation
        },
      },
    };
  },
};
</script>

Essential components

The <ais-search-box> component provides a search input field.
<ais-search-box
  placeholder="Search for products..."
  :autofocus="true"
  submit-title="Submit search"
  reset-title="Clear search"
/>

Custom rendering with slots

<ais-search-box>
  <template #submit-icon>
    <svg><!-- Custom submit icon --></svg>
  </template>
  <template #reset-icon>
    <svg><!-- Custom reset icon --></svg>
  </template>
  <template #loading-indicator>
    <span class="custom-loader">Loading...</span>
  </template>
</ais-search-box>

Hits

The <ais-hits> component displays search results.
<ais-hits>
  <template #item="{ item }">
    <article>
      <img :src="item.image" :alt="item.name" />
      <h2>
        <ais-highlight :hit="item" attribute="name" />
      </h2>
      <p>{{ item.price }}</p>
    </article>
  </template>
</ais-hits>
The item slot receives the full hit object with all attributes from your Algolia index.

Refinement list

The <ais-refinement-list> component creates a list of facet filters.
<ais-refinement-list
  attribute="brand"
  :searchable="true"
  searchable-placeholder="Search brands..."
  operator="or"
  :limit="10"
  :show-more="true"
  :show-more-limit="20"
/>

Configure

The <ais-configure> component sets search parameters without rendering UI.
<ais-configure
  :hits-per-page.camel="20"
  :attributes-to-snippet.camel="['description:50']"
  :snippet-ellipsis-text.camel="'...'"
  :remove-words-if-no-result.camel="'allOptional'"
/>
Use the .camel modifier for props with camelCase names in Vue 2. Vue 3 handles this automatically.

Highlighting and snippeting

Highlight component

Highlight matching terms in search results:
<ais-highlight
  :hit="item"
  attribute="name"
  highlighted-tag-name="mark"
/>

Snippet component

Display text snippets with highlighted matches:
<ais-snippet
  :hit="item"
  attribute="description"
  highlighted-tag-name="em"
/>

Pagination

Add pagination controls with <ais-pagination>:
<ais-pagination
  :padding="3"
  :show-first="true"
  :show-last="true"
/>
Custom pagination rendering:
<ais-pagination>
  <template #default="{ pages, currentRefinement, refine, createURL }">
    <ul>
      <li v-for="page in pages" :key="page">
        <a
          :href="createURL(page)"
          :class="{ active: page === currentRefinement }"
          @click.prevent="refine(page)"
        >
          {{ page + 1 }}
        </a>
      </li>
    </ul>
  </template>
</ais-pagination>
Search across multiple indices using the <ais-index> component:
<ais-instant-search
  :search-client="searchClient"
  index-name="products"
>
  <!-- Main index -->
  <ais-search-box />
  <ais-hits>
    <template #item="{ item }">
      <div>{{ item.name }}</div>
    </template>
  </ais-hits>

  <!-- Secondary index for suggestions -->
  <ais-index
    index-name="query_suggestions"
    index-id="suggestions"
  >
    <ais-hits>
      <template #item="{ item }">
        <div>{{ item.query }}</div>
      </template>
    </ais-hits>
  </ais-index>
</ais-instant-search>

Customizing widget UI

All widgets support custom rendering through scoped slots:
<ais-stats>
  <template #default="{ nbHits, processingTimeMS }">
    <p>
      Found <strong>{{ nbHits.toLocaleString() }}</strong> results
      in {{ processingTimeMS }}ms
    </p>
  </template>
</ais-stats>

Controlled components

Control widget state from parent components:
<template>
  <ais-search-box v-model="query" />
</template>

<script>
export default {
  data() {
    return {
      query: 'initial search',
    };
  },
};
</script>
Control when searches execute using search-function:
<template>
  <ais-instant-search
    :search-client="searchClient"
    index-name="products"
    :search-function="searchFunction"
  >
    <ais-search-box />
    <ais-hits />
  </ais-instant-search>
</template>

<script>
export default {
  methods: {
    searchFunction(helper) {
      // Only search if query has at least 3 characters
      if (helper.state.query.length >= 3) {
        helper.search();
      }
    },
  },
};
</script>

Best practices

Import liteClient instead of the full client:
import { liteClient as algoliasearch } from 'algoliasearch/lite';
The lite client is optimized for search-only operations and reduces bundle size.
Create the search client once and reuse it:
// ✅ Good: Create once
const searchClient = algoliasearch('appId', 'apiKey');

export default {
  data() {
    return { searchClient };
  },
};

// ❌ Bad: Creates new instance on every render
export default {
  data() {
    return {
      searchClient: algoliasearch('appId', 'apiKey'),
    };
  },
};
Transform items before rendering:
<ais-hits :transform-items="transformItems">
  <template #item="{ item }">
    <!-- ... -->
  </template>
</ais-hits>

<script>
export default {
  methods: {
    transformItems(items) {
      return items.map(item => ({
        ...item,
        formattedPrice: `$${item.price.toFixed(2)}`,
      }));
    },
  },
};
</script>
Set global search parameters once:
<ais-configure
  :hits-per-page.camel="20"
  :attributes-to-retrieve.camel="['name', 'price', 'image']"
/>

Next steps

Vue 2 vs Vue 3

Learn about version-specific differences

Server-side rendering

Implement SSR with Vue InstantSearch

Build docs developers (and LLMs) love