Skip to main content

Version support

Vue InstantSearch supports both Vue 2 and Vue 3 from a single package:
The package automatically selects the correct build based on your Vue version. You don’t need to install different packages or manually configure the build.

Installation

The installation is identical for both versions:
npm install vue-instantsearch algoliasearch
The package structure includes separate builds:
vue-instantsearch/
├── vue2/           # Vue 2 build
│   ├── cjs/        # CommonJS
│   └── es/         # ES modules
└── vue3/           # Vue 3 build
    ├── cjs/        # CommonJS
    └── es/         # ES modules

Plugin registration

The way you register Vue InstantSearch differs between versions:
import Vue from 'vue';
import InstantSearch from 'vue-instantsearch';
import App from './App.vue';

Vue.use(InstantSearch);

new Vue({
  render: (h) => h(App),
}).$mount('#app');

Component props

Camel case modifier

Vue 2 requires the .camel modifier for props with camelCase names in templates. Vue 3 handles this automatically.
<template>
  <ais-configure
    :hits-per-page.camel="20"
    :attributes-to-snippet.camel="['description:50']"
    :snippet-ellipsis-text.camel="'...'"
  />
</template>
While Vue 3 doesn’t require .camel, using it won’t cause errors. You can keep it for compatibility if you’re maintaining code that runs on both versions.

Slots

Slot syntax

Vue 2 and Vue 3 use different syntax for scoped slots:
<template>
  <ais-hits>
    <template slot="item" slot-scope="{ item }">
      <div>{{ item.name }}</div>
    </template>
  </ais-hits>
</template>
Vue 2.6+ also supports the # shorthand syntax, so you can use the Vue 3 syntax in Vue 2.6+ for forward compatibility.

Named slots compatibility

Both versions support named slots, but the syntax differs:
<template>
  <ais-search-box>
    <template slot="submit-icon">
      <svg><!-- icon --></svg>
    </template>
    <template slot="reset-icon">
      <svg><!-- icon --></svg>
    </template>
  </ais-search-box>
</template>

V-model

Two-way binding

Vue 3 introduces modelValue as the default v-model prop, while Vue 2 uses value:
<template>
  <ais-search-box :value="query" @input="query = $event" />
  <!-- or using v-model -->
  <ais-search-box v-model="query" />
</template>

<script>
export default {
  data() {
    return {
      query: '',
    };
  },
};
</script>
Vue InstantSearch components support both value and modelValue props for compatibility.

Composition API

Vue 3’s Composition API is fully supported:
<template>
  <ais-instant-search
    :search-client="searchClient"
    index-name="products"
  >
    <ais-search-box v-model="query" />
    <ais-hits>
      <template #item="{ item }">
        <div @click="handleClick(item)">{{ item.name }}</div>
      </template>
    </ais-hits>
  </ais-instant-search>
</template>

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

const searchClient = algoliasearch('appId', 'apiKey');
const query = ref('');

const handleClick = (item) => {
  console.log('Clicked:', item);
};
</script>
The Composition API is also available in Vue 2.7+ via the @vue/composition-api plugin.

Server-side rendering

SSR implementation differs between versions due to different rendering APIs:
import { createServerRootMixin } from 'vue-instantsearch';
import _renderToString from 'vue-server-renderer/basic';

function renderToString(app) {
  return new Promise((resolve, reject) => {
    _renderToString(app, (err, res) => {
      if (err) reject(err);
      resolve(res);
    });
  });
}

export default {
  mixins: [
    createServerRootMixin({
      searchClient,
      indexName: 'products',
    }),
  ],
  serverPrefetch() {
    return this.instantsearch.findResultsState({
      component: this,
      renderToString,
    });
  },
  beforeMount() {
    if (window.__ALGOLIA_STATE__) {
      this.instantsearch.hydrate(window.__ALGOLIA_STATE__);
    }
  },
};

TypeScript support

Vue 3 has better TypeScript support out of the box:
Vue 3 with TypeScript
<script setup lang="ts">
import { ref, Ref } from 'vue';
import { liteClient as algoliasearch } from 'algoliasearch/lite';
import type { SearchClient } from 'algoliasearch/lite';

const searchClient: SearchClient = algoliasearch(
  'appId',
  'apiKey'
);

const query: Ref<string> = ref('');

interface Product {
  objectID: string;
  name: string;
  price: number;
}

const handleClick = (item: Product): void => {
  console.log('Clicked:', item);
};
</script>

Migration checklist

When migrating from Vue 2 to Vue 3:
1

Update Vue and build tools

Upgrade to Vue 3 and update your build configuration (Vite, Webpack, etc.)
2

Update slot syntax

Replace slot and slot-scope with # shorthand:
<!-- Before -->
<template slot="item" slot-scope="{ item }">

<!-- After -->
<template #item="{ item }">
3

Remove .camel modifiers

Vue 3 handles prop case conversion automatically:
<!-- Before -->
<ais-configure :hits-per-page.camel="20" />

<!-- After -->
<ais-configure :hits-per-page="20" />
4

Update SSR implementation

Use @vue/server-renderer instead of vue-server-renderer
5

Test all components

Verify that all InstantSearch components work as expected

Compatibility table

FeatureVue 2Vue 3Notes
Plugin registrationVue.use()app.use()Different APIs
Scoped slotsslot-scope# or v-slotVue 2.6+ supports both
Prop case.camel modifierAutomaticVue 3 auto-converts
v-modelvalue + inputmodelValue + update:modelValueBoth supported
SSR renderervue-server-renderer@vue/server-rendererDifferent packages
Composition APIVia plugin (2.7+)Built-inNative in Vue 3
TypeScriptLimitedFull supportBetter DX in Vue 3
Fragment supportNoYesMultiple root elements
TeleportNoYesPortal-like feature

Best practices

Even in Vue 2.6+, prefer the # shorthand for better forward compatibility:
<!-- ✅ Recommended -->
<template #item="{ item }">

<!-- ❌ Avoid -->
<template slot="item" slot-scope="{ item }">
For better performance, don’t make the search client reactive:
// ✅ Good
import { liteClient as algoliasearch } from 'algoliasearch/lite';

const searchClient = algoliasearch('appId', 'apiKey');

export default {
  data() {
    return { searchClient };
  },
};
The <script setup> syntax provides better performance and DX:
<script setup>
import { ref } from 'vue';
import { liteClient as algoliasearch } from 'algoliasearch/lite';

const searchClient = algoliasearch('appId', 'apiKey');
const query = ref('');
</script>

Next steps

Server-side rendering

Learn how to implement SSR with Vue InstantSearch

Component reference

Explore all available components and their props

Build docs developers (and LLMs) love