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:
< 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:
Update Vue and build tools
Upgrade to Vue 3 and update your build configuration (Vite, Webpack, etc.)
Update slot syntax
Replace slot and slot-scope with # shorthand: <!-- Before -->
< template slot = "item" slot-scope = "{ item }" >
<!-- After -->
< template # item = " { item } " >
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 " />
Update SSR implementation
Use @vue/server-renderer instead of vue-server-renderer
Test all components
Verify that all InstantSearch components work as expected
Compatibility table
Feature Vue 2 Vue 3 Notes Plugin registration Vue.use()app.use()Different APIs Scoped slots slot-scope# or v-slotVue 2.6+ supports both Prop case .camel modifierAutomatic Vue 3 auto-converts v-model value + inputmodelValue + update:modelValueBoth supported SSR renderer vue-server-renderer@vue/server-rendererDifferent packages Composition API Via plugin (2.7+) Built-in Native in Vue 3 TypeScript Limited Full support Better DX in Vue 3 Fragment support No Yes Multiple root elements Teleport No Yes Portal-like feature
Best practices
Use the modern slot syntax
Even in Vue 2.6+, prefer the # shorthand for better forward compatibility: <!-- ✅ Recommended -->
< template # item = " { item } " >
<!-- ❌ Avoid -->
< template slot = "item" slot-scope = "{ item }" >
Keep the search client outside of reactive data
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 };
} ,
} ;
Consider using script setup in Vue 3
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