Guides / Building Search UI

Upgrading InstantSearch.js

Upgrade templates

Starting from InstantSearch.js v4.46.0, string-based and Hogan.js templates are deprecated.

If you’re using Hogan.js templates or HTML strings using string-based templates, you can replace them either with safe HTML strings using the provided html tagged template, or JSX templates.

These new templating options are safer against cross-site scripting (XSS) attacks, perform better, and are more accessible, because they reuse and patch the existing DOM instead of replacing it entirely at each render.

Interpolation

You can interpolate dynamic values using template literals placeholders.

All available dynamic values are exposed within the scope of the template function.

1 2 3 4 5 6 7 8 
toggleRefinement({// ...templates:{labelText({count},{html}){returnhtml`Free shipping (${count})`;},},});

Highlighting and snippeting

In both hits and infiniteHits widgets, templates expose a set of built-in components to handle highlighting and snippeting.

1 2 3 4 5 6 7 8 9 10 11 
hits({// ...templates:{item(hit,{html,components}){returnhtml` <h2>${components.Highlight({hit,attribute:'name'})}</h2> <p>${components.Snippet({hit,attribute:'description'})}</p> `;},},});

Loops

You can use plain JavaScript to build dynamic templates.

For example, you can use Array.mapto loop over an array and display a list.

1 2 3 4 5 6 7 8 9 10 
ratingMenu({// …templates:{item({url,stars},{html}){returnhtml`<a href="${url}"> ${stars.map((_,index)=>html`<svg key="${index}"><!-- … --></svg>`)} </a>`;},},});

Passing a unique key attribute is helpful when mapping over items. It helps the virtual DOM keep track of each element when they change, and update the UI efficiently.

Conditional rendering

To conditionally render a part of your UI, you can use a short-circuit operator or a ternary.

Since templates are functions, you can also use early returns to provide alternative templates.

1 2 3 4 5 6 7 8 9 10 11 12 
stats({// …templates:{text({nbHits},{html}){if(nbHits===0){returnhtml`<p>No results.</p>`;}returnhtml`<p>${nbHits} result${nbHits>1?'s':''} found.</p>`;},},});

Upgrade event tracking

Starting from v4.55.0, InstantSearch simplifies the event tracking process with the insights option. You no longer need to install the search-insights library or set up the insights middleware yourself.

Here are some benefits when using the insights option:

  • It better handles the userToken. Once you set it, all the search and event tracking calls include the token.
  • It automatically sends default events from built-in widgets such as refinementList, menu, etc. You can also change the event payloads, or remove them altogether.
  • It lets you send custom events from your custom widgets.
  • It simplifies forwarding events to third-party trackers.

If you’ve been tracking events directly with search-insights or with the insights middleware, you should:

  1. Upgrade InstantSearch.js to v4.55.0 or greater
  2. Migrate from using the insights middleware to the insights option
  3. Either update or remove the search-insights library

Use the insights option

Starting from v4.55.0, InstantSearch lets you enable event tracking with the insights option. You no longer need to set up the insights middleware yourself.

1 2 3 4 
constsearch=instantsearch({// …insights:true,});

If you had already set up the insights middleware in your code, you can now remove it and move its configuration to the insights option.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
- import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares'; const search = instantsearch({  insights: { + insightsInitParams: { + useCookie: false, + },  }, }); - search.use( - createInsightsMiddleware({ - insightsInitParams: { - useCookie: false, - }, - }) - ); 

Update search-insights

Starting from v4.55.0, InstantSearch can load search-insights for you so the insightsClient option is no longer required.

If you prefer loading it yourself, make sure to update search-insights to at least v2.4.0 and forward the reference to insights.

If you’re using the UMD bundle with a <script> tag, make sure to update the full code snippet (not just the version):

1 2 3 4 5 6 7 8 
<script>varALGOLIA_INSIGHTS_SRC="https://cdn.jsdelivr.net/npm/search-insights@2.17.3/dist/search-insights.min.js";!function(e,a,t,n,s,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){(e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(/@([^\/]+)\/?/)||[])[1],i=a.createElement(t),c=a.getElementsByTagName(t)[0],i.async=1,i.src=n,c.parentNode.insertBefore(i,c)}(window,document,"script",ALGOLIA_INSIGHTS_SRC,"aa");</script>

If you’re using a package manager, you can upgrade it to the latest version.

1 
npm install search-insights 

Now you can pass the reference to the insights option.

1 2 3 4 5 
constsearch=instantsearch({insights:{insightsClient:window.aa,},});

Otherwise, you can remove it and let InstantSearch handle it for you.

Remove search-insights

Starting from v4.55.0, InstantSearch loads search-insights for you from jsDelivr if not detected in the page. If you’ve installed search-insights, you can now remove it.

If you’re using the UMD bundle with a <script> tag, you can remove the snippet in any page that uses InstantSearch:

1 2 3 4 5 6 7 8 
- <script> - var ALGOLIA_INSIGHTS_SRC = "https://cdn.jsdelivr.net/npm/search-insights@2.17.3/dist/search-insights.min.js"; - - !function(e,a,t,n,s,v,i,c){e.AlgoliaAnalyticsObject=s,e[s]=e[s]||function(){ - (e[s].queue=e[s].queue||[]).push(arguments)},e[s].version=(n.match(/@([^\/]+)\/?/) || [])[1],i=a.createElement(t),c=a.- getElementsByTagName(t)[0], - i.async=1,i.src=n,c.parentNode.insertBefore(i,c) - }(window,document,"script",ALGOLIA_INSIGHTS_SRC,"aa"); - </script> 

If you’re using a package manager, you can remove it from your dependencies.

1 
npm uninstall search-insights 

Then you can remove the reference to search-insights from your code:

1 2 3 4 5 
const search = instantsearch({  insights: { - insightsClient: window.aa,  }, }); 

InstantSearch loads search-insights from the jsDelivr CDN, which requires that your site or app allows script execution from foreign resources. Check the security best practices for recommendations.

No longer needed configuration

clickAnalytics: true

1 2 3 
instantsearch.widgets.configure({clickAnalytics:true,}),

This isn’t needed anymore because it’s automatically added by the middleware.

getInsightsAnonymousUserToken()

1 2 3 
instantsearch.widgets.configure({userToken:instantsearch.getInsightsAnonymousUserToken()});

You no longer need this. Once you integrate the insights middleware, it initially sets the anonymous userToken. As soon as you set another userToken, it automatically syncs it between search and analytics calls.

insightsClient at InstantSearch

1 2 3 4 5 
constsearch=instantsearch({searchClient,indexName:'INDEX_NAME',insightsClient:window.aa,});

Now that you are using the Insights middleware, you don’t need to pass aa to instantsearch() anymore.

hits and infiniteHits template

You might have templates in your hits or infiniteHits widgets that look like the following:

1 2 3 4 5 6 7 8 
<button${instantsearch.insights('convertedObjectIDsAfterSearch',{eventName:'ProductAdded',objectIDs:[hit.objectID]})}> Add to cart </button>

These are now deprecated. Instead, you can use the sendEvent function.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
instantsearch.widgets.hits({container:'#hits',templates:{item(hit,{html,sendEvent,components}){returnhtml` <article> <h3>${components.Highlight({attribute:'name',hit})}</h3> <button onClick=${()=>sendEvent('conversion',hit,'Product Added')} > Add to cart <!-- clicking this button sends a `conversion` event --> </button> </article> `;}}})

analytics widget

The analytics widget has been deprecated in favor of the insights middleware.

When the built-in widgets trigger default events, you can intercept them using the insights middleware’s onEvent hook and send them to third-party trackers.

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 
import{createInsightsMiddleware}from'instantsearch.js/es/middlewares';// Or, use `instantsearch.middlewares.createInsightsMiddleware()`constindexName='<your-index-name>';constsearch=instantsearch({indexName,// ...});constinsightsMiddleware=createInsightsMiddleware({insightsClient:window.aa,onEvent:(event,aa)=>{const{insightsMethod,payload,widgetType,eventType}=event;// Send the event to Algoliaaa(insightsMethod,payload);// Send click events on Hits to a third-party trackerif(widgetType==='ais.hits'&&eventType==='click'){thirdPartyTracker.send('Product Clicked',payload);}}});search.use(insightsMiddleware);

If you want to send events every time the query or refinements change, you can add a custom middleware to listen to uiState changes with the onStateChange function.

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 
constindexName='<your-index-name>';constsearch=instantsearch({indexName,// ...});constanalyticsMiddleware=()=>{return{onStateChange({uiState}){// Google Analytics (Universal Analytics)window.ga('set','page',window.location.pathname+window.location.search);window.ga('send','pageView');// Google Analytics V4gtag('event','page_view',{page_location:window.location.pathname+window.location.search,});// Google Tag Manager (GTM)// You can use `uiState` to make payloads for third-party trackers.dataLayer.push({'event':'search','Search Query':uiState[indexName].query,'Brand':uiState[indexName].refinementList['brand'].join(','),});},subscribe(){},unsubscribe(){},}}search.use(analyticsMiddleware);

You can also use external libraries like lodash.debounce to debounce the events you send.

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 
importdebouncefrom'lodash.debounce';constindexName='<your-index-name>';constsearch=instantsearch({indexName,// ...});constsendEventDebounced=debounce((uiState)=>{// Google Analyticswindow.ga('set','page',window.location.pathname+window.location.search);window.ga('send','pageView');// Google Analytics V4gtag('event','page_view',{page_location:window.location.pathname+window.location.search,});// Google Tag Manager (GTM)dataLayer.push({'event':'search','Search Query':uiState[indexName].query,'Brand':uiState[indexName].refinementList['brand'].join(','),});},3000);constanalyticsMiddleware=()=>{return{onStateChange({uiState}){sendEventDebounced(uiState);},subscribe(){},unsubscribe(){},}}search.use(analyticsMiddleware);

Upgrade to Recommend

The relatedProducts widget is now available instead of the previous experimental widget EXPERIMENTAL_relatedItems. To migrate, you change the widget name and update the props:

1 2 3 4 5 6 7 8 9 10 11 12 13 
- import { EXPERIMENTAL_relatedItems } from 'instantsearch.js/es/widgets'; + import { relatedProducts } from 'instantsearch.js/es/widgets'; search.addWidgets([ - EXPERIMENTAL_relatedItems({ - hit: { objectID: '123' }, - }), - hits({ container: '#related-products' }), + relatedProducts({ + container: '#related-products', + objectIDs: ['123'], + }), ]); 

Upgrade from v3 to v4

The latest version of InstantSearch mostly focuses on federated search and bundle size. This required some changes that might impact your app.

Federated search (multi-index)

If you were already using federated search (for example by synchronizing two instantsearch instances via the searchFunction), the implementation is now simpler. Instead, try the new index widget, to which you can attach more widgets. For example:

1 2 3 4 5 6 7 8 9 10 
constsearch=instantsearch({indexName:'primary',/* ... */});search.addWidgets([searchBox(),hits(),index({indexName:'secondary'}).addWidgets([searchBox(),hits(),])]);

Routing

Even if you aren’t using multi-index search, the way in which uiState is stored has changed. It used to look like this:

1 2 3 4 
{"query":"value","page":5}

It now looks like this:

1 2 3 4 5 6 
{"indexName":{"query":"value","page":5}}

If you are using the default state mapping (simpleStateMapping) with the current version, you can replace it with singleIndexStateMapping('yourIndexName'). You have to change the code as followed:

1 2 3 4 5 6 7 8 
 instantsearch({ indexName: 'myIndex', routing: { - stateMapping: instantsearch.stateMappings.simple(), + stateMapping: instantsearch.stateMappings.singleIndex('myIndex'),  } // ... }); 

If you are using a custom state mapping, you have to loop over the outer level of the index widget and add this extra level to the routeToState. You can check the source for a reference on how to implement this.

For example, a stateMapping that maps a few properties would change like this:

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 
// BeforeconststateMapping={stateToRoute(uiState){return{query:uiState.query,page:uiState.page,// ...};},routeToState(routeState){return{query:routeState.query,page:routeState.page,// ...};},};// AfterconststateMapping={stateToRoute(uiState){constindexUiState=uiState[indexName];return{query:indexUiState.query,page:indexUiState.page,// ...};},routeToState(routeState){return{[indexName]:{query:routeState.query,page:routeState.page,// ...},};},};

Configure

The configure widget is now included in uiState. If you want to exclude it from the URL you can use the default stateMappings or exclude it in your custom state mapping. A good reason to exclude the configure widget from the UI state is to prevent users from adding any search parameters.

You must exclude this widget in both the stateToRoute, to keep it from appearing in the URL and routeToState, so that the URL doesn’t apply to the state.

Check the stateMapping source code for implementation details.

Algolia search helper

This release includes version 3 of the algoliasearch-helper package. If you’re using the built-in widgets or connectors, nothing changes for you.

This version of algoliasearch-helper no longer includes Lodash, which reduces its bundle size (from 27.5 KB to 9.1 KB Gzipped). If you’re using any methods from the helper, searchParameters or searchResults, refer to the package’s change log.

searchParameters

The option searchParameters was removed from the instantsearch widget. You can replace it with the configure widget, like this:

1 2 3 4 5 6 7 8 9 10 11 12 
const search = instantsearch({  // ... - searchParameters: { - hitsPerPage: 5, - }, }); + search.addWidgets([ + instantsearch.widgets.configure({ + hitsPerPage: 5, + }), + ]); 

You can now add initialUiState to your InstantSearch widget. This overwrites specific searchParameters that are otherwise set during widget instantiation. initialUiState is only taken into account if a widget owning that “state” is mounted. A warning appears in development mode explaining which widget needs to be added for the UI state to have an effect.

An example is a refinementList widget:

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 
const search = instantsearch({  // ... - searchParameters: { - disjunctiveFacets: ['brand'], - disjunctiveFacetsRefinements: { - brand: ['Apple'], - }, - }, + initialUiState: { + refinementList: { + brand: ['Apple'], + }, + }, }); search.addWidgets([  refinementList({ attribute: 'brand' }), ]); // or when there should be no display for this widget: const virtualRefinementList = connectRefinementList(() => null); search.addWidgets([  virtualRefinementList({ attribute: 'brand' }), ]); 

addWidget and removeWidget

The search.addWidget function is deprecated in favor of search.addWidgets, which accepts an array of widgets.

Using arrays makes it clearer to see the structure of nested widgets. search.removeWidget is deprecated in favor of search.removeWidgets, which also accepts an array of widgets.

Places.js widget

The widget which used to ship with Places.js is no longer compatible with InstantSearch. It has been replaced with one that ships directly with InstantSearch.js.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 
importalgoliaPlacesfrom'places.js';import{places}from'instantsearch.js/es/widgets';constsearch=instantsearch({/* ... */});search.addWidgets([places({placesReference:algoliaPlaces,defaultPosition:['37.7793','-122.419'],// optionalcontainer:'#places',}),]);

The widget parameters are:

  • placesReference: the places.js library.
  • defaultPosition: the coordinates to use if users don’t choose a location.
  • container: the DOM element to mount the input into.
  • ...other: places.js options

Custom widgets

Because version 3 of the algoliasearch-helper package is used, you have to replace the getConfiguration lifecycle with getWidgetSearchParameters and getWidgetState.

This also means that your custom widget takes part in the routing. You can exclude it from the URL via stateMapping.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
constwidget={getConfiguration(searchParams){return{disjunctiveFacets:['myAttribute'],};},getWidgetSearchParameters(searchParameters,{uiState}){returnsearchParameters.addDisjunctiveFacetRefinement('myAttribute',uiState.myWidgetName.myAttribute);},getWidgetState(uiState,{searchParameters}){return{...uiState,myWidgetName:{myAttribute:searchParameters.getDisjunctiveRefinements('myAttribute')}};}};

Becomes:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
constwidget={getWidgetSearchParameters(searchParameters,{uiState}){returnsearchParameters.addDisjunctiveFacet('myAttribute').addDisjunctiveFacetRefinement('myAttribute',uiState.myWidgetName.myAttribute);},getWidgetState(uiState,{searchParameters}){return{...uiState,myWidgetName:{myAttribute:searchParameters.getDisjunctiveRefinements('myAttribute')}};}};

connectAutoComplete

The indices option was removed in favor of index widgets (see the federated search section). For example, the following code:

1 2 3 4 5 6 7 8 9 
constautocomplete=connectAutocomplete(()=>{/* ... */});search.addWidget(autocomplete({indices:[{name:'additional'}]}));

Should be replaced with this:

1 2 3 4 5 6 
constautocomplete=connectAutocomplete(()=>{/* ... */});search.addWidgets([index({indexName:'additional'}),autocomplete()]);

onHistoryChange

The onHistoryChange function is removed. To subscribe to changes in the URL, create a custom router and attach to the write hook. For example:

1 2 3 4 5 6 
constrouter=historyRouter()constoriginalWrite=router.write.bind(router)router.write=state=>{console.log('listen to route state here');originalWrite(state)}

router

The dispose function on the router interface is now required and its signature is updated (see the example below). This change only impacts you if you use a custom router.

1 2 3 4 5 6 7 
interfaceRouter{// ...// Beforedispose?({helper,state}:{helper:AlgoliaSearchHelper,state:SearchParameters}):SearchParameters|void// Afterdispose():void}

pagination

The noRefinementRoot CSS class gets added once there are no more possible refinements. It no longer gets applied on the first page, which was the wrong behavior.

Upgrade from v2 to v3

InstantSearch v3 introduces some breaking changes in the widgets’ naming, options, and markup.

What’s new

Search from your own search client

Since InstantSearch.js 2.8.0, it’s possible to search from your own backend using the searchClient option.

This option is now the way to plug InstantSearch to either Algolia’s official JavaScript client or to yours. This means that the official search client isn’t bundled in InstantSearch, allowing for more flexibility. This results in a smaller bundle size when you’re not searching directly from the frontend, or that you use multiple instances of the search client.

Predictable DOM structure

InstantSearch.js v3 becomes more predictable by generating a DOM that follows Algolia’s InstantSearch.css specification. All flavors are now aligned, which makes it easier to migrate from one library flavor to another. The options and the DOM output are similar whether you use React InstantSearch, Vue InstantSearch, Angular InstantSearch or InstantSearch.js.

Optimize InstantSearch based on your environment

The new bundle comes in two forms:

  • Development bundle. This is a heavier bundle that helps developers better debug in the development phase of an InstantSearch app. It’s more verbose and gives clues and warnings about the library usage.
  • Production bundle. This is a lighter bundle that doesn’t include any development warnings. Use this when deploying your app in a production environment.

Imports

UMD (Universal Module Definition)

New naming has been introduced for the UMD imports. This makes it clearer which InstantSearch.js bundle to use either in development or in production. The production bundle will get lighter over time as it won’t include the runtime warnings and documentation.

Before
1 2 3 4 5 
dist ├── instantsearch.js ├── instantsearch.js.map ├── instantsearch.min.js └── instantsearch.min.js.map 
After
1 2 3 4 5 
dist ├── instantsearch.development.js ├── instantsearch.development.js.map ├── instantsearch.production.min.js └── instantsearch.production.min.js.map 

CommonJS (CJS)

Before
1 
constinstantsearch=require('instantsearch.js');
After
1 
constinstantsearch=require('instantsearch.js').default;

ES (ECMAScript)

No changes.

InstantSearch

The variables appId and apiKey are replaced by searchClient.

Earlier usage

  1. Import InstantSearch.js
  2. Initialize InstantSearch
1 2 3 4 5 6 7 
constsearch=instantsearch({indexName:'indexName',appId:'appId',apiKey:'apiKey',});search.start();
New usage
  1. Import algoliasearch (prefer the lite version for search only)
  2. Import InstantSearch.js
  3. Initialize InstantSearch with the searchClient option
1 2 3 4 5 6 
constsearch=instantsearch({indexName:'indexName',searchClient:algoliasearch('appId','apiKey'),});search.start();

transformData is replaced by transformItems

Since InstantSearch.js first public release, you can customize the values used in the widgets. This method was letting you map 1-1 the values with other values. With React InstantSearch, a slightly different API was implemented that lets you map over the list of values and to change their content.

Earlier usage
1 2 3 4 5 6 7 8 9 10 11 12 
search.addWidgets([instantsearch.widget.refinementList({container:'#facet',attributeName:'facet',transformData:{item:data=>{data.count=0;returndata;},},})]);
New usage
1 2 3 4 5 6 7 8 9 10 11 
search.addWidgets([instantsearch.widget.refinementList({container:'#facet',attribute:'facet',transformItems:items=>items.map(item=>({...item,count:0,})),})]);

instantsearch.highlight and instantsearch.snippet

Highlighting is a powerful tool for showing users why results match their queries. Previously, InstantSearch used internal mechanisms or Hogan.js to implement highlighting within widget templates. Algolia now provides html tagged templates.

Earlier usage
1 2 3 4 5 6 7 8 
search.addWidgets([instantsearch.widget.hits({container:'#hits',templates:{item:'{{{ _highlightResult.name.value }}}',},})]);
New usage
1 2 3 4 5 6 7 8 
search.addWidgets([instantsearch.widget.hits({container:'#hits',templates:{item:(hit,{components})=>components.Highlight({attribute:'name',hit}),},})]);

urlSync is dropped

If you were previously using the urlSync option, you should now migrate to the new routing feature.

Here are the elements you need to migrate:

  • urlSync: true becomes routing: true
  • threshold becomes routing: { router: instantsearch.routers.history({ writeDelay: 400 }) }
  • mapping and trackedParameters are replaced with stateMapping. Read “User friendly URLs” to know how to configure it
  • useHash is removed but can be achieved using an advanced configuration of the history router
  • getHistoryState is removed but can be achieved using an advanced configuration of the history router

collapsible is dropped

collapsible is replaced by the collapsed option in the panel widget.

autoHideContainer is dropped

autoHideContainer is replaced by the hidden option in the panel widget.

createAlgoliaClient is dropped

createAlgoliaClient is replaced by searchClient.

createQueryString is dropped

URL synchronization is done via Routing alone now.

Widgets

CSS classes
BeforeAfter
ais-breadcrumbais-Breadcrumb
 ais-Breadcrumb--noRefinement
ais-breadcrumbais-Breadcrumb-list
ais-breadcrumb--separatorais-Breadcrumb-separator
ais-breadcrumb--labelais-Breadcrumb-link
ais-breadcrumb--disabledLabel 
 ais-Breadcrumb-item
 ais-Breadcrumb-item--selected
Markup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
<divclass="ais-Breadcrumb"><ulclass="ais-Breadcrumb-list"><liclass="ais-Breadcrumb-item"><aclass="ais-Breadcrumb-link"href="#">Home</a></li><liclass="ais-Breadcrumb-item"><spanclass="ais-Breadcrumb-separator"aria-hidden="true">></span><aclass="ais-Breadcrumb-link"href="#">Cooking</a></li><liclass="ais-Breadcrumb-item ais-Breadcrumb-item--selected"><spanclass="ais-Breadcrumb-separator"aria-hidden="true">></span> Kitchen textiles </li></ul></div>

ClearRefinements (formerly ClearAll)

Options
BeforeAfter
excludeAttributesexcludedAttributes
CSS classes
BeforeAfter
ais-clear-allais-ClearRefinements
ais-clear-all--body 
ais-clear-all--link 
 ais-ClearRefinements-button
 ais-ClearRefinements-button--disabled
Markup
1 2 3 4 5 
<divclass="ais-ClearRefinements"><buttonclass="ais-ClearRefinements-button"> Clear refinements </button></div>

CurrentRefinements (formerly CurrentRefinedValues)

Options
BeforeAfter
attributesincludedAttributes
 excludedAttributes
onlyListedAttributesuse includedAttributes
clearsQueryuse excludedAttributes
clearAlluse the clearRefinements widget
  • clearsQuery can be replaced by excludedAtributes: [].
CSS classes
BeforeAfter
ais-current-refined-valuesais-CurrentRefinements
ais-current-refined-values--listais-CurrentRefinements-list
ais-current-refined-values--itemais-CurrentRefinements-item
ais-current-refined-values--linkais-CurrentRefinements-label
ais-current-refined-values--count 
 ais-CurrentRefinements-category
 ais-CurrentRefinements-categoryLabel
 ais-CurrentRefinements-delete
 ais-CurrentRefinements-query
ais-current-refined-values--clear-all 
Markup
Default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
<divclass="ais-CurrentRefinements"><ulclass="ais-CurrentRefinements-list"><liclass="ais-CurrentRefinements-item"><spanclass="ais-CurrentRefinements-label"> Category: </span><spanclass="ais-CurrentRefinements-category"><spanclass="ais-CurrentRefinements-categoryLabel">Movies & TV Shows</span><buttonclass="ais-CurrentRefinements-delete"></button></span><spanclass="ais-CurrentRefinements-category"><spanclass="ais-CurrentRefinements-categoryLabel">Others</span><buttonclass="ais-CurrentRefinements-delete"></button></span></li></ul></div>
With includesQuery and a query
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 
<divclass="ais-CurrentRefinements"><ulclass="ais-CurrentRefinements-list"><liclass="ais-CurrentRefinements-item"><spanclass="ais-CurrentRefinements-label"> Category: </span><spanclass="ais-CurrentRefinements-category"><spanclass="ais-CurrentRefinements-categoryLabel">Movies & TV Shows</span><buttonclass="ais-CurrentRefinements-delete"></button></span><spanclass="ais-CurrentRefinements-category"><spanclass="ais-CurrentRefinements-categoryLabel">Others</span><buttonclass="ais-CurrentRefinements-delete"></button></span></li><liclass="ais-CurrentRefinements-item"><spanclass="ais-CurrentRefinements-label"> Query: </span><spanclass="ais-CurrentRefinements-category"><spanclass="ais-CurrentRefinements-categoryLabel"><q>My query</q></span><buttonclass="ais-CurrentRefinements-delete"></button></span></li></ul></div>
Options
BeforeAfter
customHTMLMarker.templatetemplates.HTMLMarker
paddingBoundingBoxRemoved
enableGeolocationWithIPRemoved - use the Configure widget instead (see below)
positionRemoved - use the Configure widget instead (see below)
radiusRemoved - use the Configure widget instead (see below)
precisionRemoved - use the Configure widget instead (see below)

Since paddingBoundingBox conflicted with the routing option it was removed to support URLSync for the GeoSearch widget.

enableGeolocationWithIP

Before:

1 2 3 4 5 
instantsearch.widgets.geoSearch({googleReference:window.google,enableGeolocationWithIP:true,container,});

After:

1 2 3 4 5 6 7 8 
instantsearch.widgets.configure({aroundLatLngViaIP:true,});instantsearch.widgets.geoSearch({googleReference:window.google,container,});
position

Before:

1 2 3 4 5 
instantsearch.widgets.geoSearch({googleReference:window.google,position:{lat:40.71,lng:-74.01},container,});

After:

1 2 3 4 5 6 7 8 
instantsearch.widgets.configure({aroundLatLng:'40.71, -74.01',});instantsearch.widgets.geoSearch({googleReference:window.google,container,});
radius

Before:

1 2 3 4 5 
instantsearch.widgets.geoSearch({googleReference:window.google,radius:1000,container,});

After:

1 2 3 4 5 6 7 8 
instantsearch.widgets.configure({aroundRadius:1000,});instantsearch.widgets.geoSearch({googleReference:window.google,container,});
precision

Before:

1 2 3 4 5 
instantsearch.widgets.geoSearch({googleReference:window.google,precision:1000,container,});

After:

1 2 3 4 5 6 7 8 
instantsearch.widgets.configure({aroundPrecision:1000,});instantsearch.widgets.geoSearch({googleReference:window.google,container,});
CSS classes
BeforeAfter
ais-geo-searchais-GeoSearch
ais-geo-search--mapais-GeoSearch-map
ais-geo-search--controlsais-GeoSearch-tree
ais-geo-search--controlais-GeoSearch-control
ais-geo-search--toggle-labelais-GeoSearch-label
ais-geo-search--toggle-label-activeais-GeoSearch-label--selected
ais-geo-search--toggle-inputais-GeoSearch-input
ais-geo-search--redoais-GeoSearch-redo
 ais-GeoSearch-redo--disabled
ais-geo-search--clearais-GeoSearch-reset
Markup

With the control element:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
<divclass="ais-GeoSearch"><divclass="ais-GeoSearch-map"><!-- Map element here --></div><divclass="ais-GeoSearch-tree"><divclass="ais-GeoSearch-control"><labelclass="ais-GeoSearch-label"><inputclass="ais-GeoSearch-input"type="checkbox"> Search as I move the map </label></div><buttonclass="ais-GeoSearch-reset"> Clear the map refinement </button></div></div>

With the redo button:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
<divclass="ais-GeoSearch"><divclass="ais-GeoSearch-map"><!-- Map element here --></div><divclass="ais-GeoSearch-tree"><divclass="ais-GeoSearch-control"><buttonclass="ais-GeoSearch-redo"> Redo search here </button></div><buttonclass="ais-GeoSearch-reset"> Clear the map refinement </button></div></div>

Hits

Options
BeforeAfter
escapeHitsescapeHTML
showMoreLabelloadMoreLabel
  • escapeHTML becomes true by default.
  • allItems template has been removed in favor of connectHits
CSS classes
BeforeAfter
ais-hitsais-Hits
ais-hits--emptyais-Hits--empty
 ais-Hits--list
ais-hits--itemais-Hits--item
Markup
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 
<divclass="ais-Hits"><olclass="ais-Hits-list"><liclass="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li></ol></div>

HitPerPage (formerly HitsPerPageSelector)

Options
BeforeAfter
attributeNameattribute
CSS classes
BeforeAfter
 ais-HitsPerPage
ais-hits-per-page-selectorais-HitsPerPage-select
ais-hits-per-page--itemais-HitsPerPage-option
Markup
1 2 3 4 5 6 
<divclass="ais-HitsPerPage"><selectclass="ais-HitsPerPage-select"><optionclass="ais-HitsPerPage-option"value="3">3 per page</option><optionclass="ais-HitsPerPage-option"value="6">6 per page</option></select></div>

Infinite hits

Options
BeforeAfter
escapeHitsescapeHTML
loadMoreLabeltemplates.showMoreText
  • escapeHTML defaults to true
CSS classes
BeforeAfter
ais-infinite-hitsais-InfiniteHits
ais-infinite-hits--emptyais-InfiniteHits--empty
 ais-InfiniteHits--list
ais-infinite-hits--itemais-InfiniteHits--item
ais-infinite-hits--showmore 
ais-infinite-hits--showmoreButtonais-InfiniteHits-loadMore
 ais-InfiniteHits-loadMore--disabled
Markup
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 
<divclass="ais-InfiniteHits"><olclass="ais-InfiniteHits-list"><liclass="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li><liclass="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li><liclass="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li></ol><buttonclass="ais-InfiniteHits-loadMore">Show more results</button>

Hierarchical menu

Options
BeforeAfter
 showMore
 showMoreLimit
CSS classes
BeforeAfter
ais-hierarchical-menuais-HierarchicalMenu
 ais-HierarchicalMenu--noRefinement
 ais-HierarchicalMenu-searchBox
ais-hierarchical-menu--listais-HierarchicalMenu-list
 ais-HierarchicalMenu-list--child
 ais-HierarchicalMenu-list--lvl0
 ais-HierarchicalMenu-list--lvl1
ais-hierarchical-menu--itemais-HierarchicalMenu-item
ais-hierarchical-menu--item__activeais-HierarchicalMenu-item--selected
ais-hierarchical-menu--item__parentais-HierarchicalMenu-item--parent
ais-hierarchical-menu--linkais-HierarchicalMenu-link
ais-hierarchical-menu--labelais-HierarchicalMenu-label
ais-hierarchical-menu--countais-HierarchicalMenu-count
ais-hierarchical-menu--noResultsais-HierarchicalMenu-noResults
 ais-HierarchicalMenu-showMore
 ais-HierarchicalMenu-showMore--disabled
Markup
Default
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 
<divclass="ais-HierarchicalMenu"><ulclass="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--lvl0"><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent ais-HierarchicalMenu-item--selected"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Appliances</span><spanclass="ais-HierarchicalMenu-count">4,306</span></a><ulclass="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--child ais-HierarchicalMenu-list--lvl1"><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Dishwashers</span><spanclass="ais-HierarchicalMenu-count">181</span></a></li><liclass="ais-HierarchicalMenu-item"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Fans</span><spanclass="ais-HierarchicalMenu-count">91</span></a></li></ul></li><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Audio</span><spanclass="ais-HierarchicalMenu-count">1,570</span></a></li></ul><buttonclass="ais-HierarchicalMenu-showMore">Show more</button></div>
Show more disabled
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 
<divclass="ais-HierarchicalMenu"><ulclass="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--lvl0"><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent ais-HierarchicalMenu-item--selected"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Appliances</span><spanclass="ais-HierarchicalMenu-count">4,306</span></a><ulclass="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--child ais-HierarchicalMenu-list--lvl1"><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Dishwashers</span><spanclass="ais-HierarchicalMenu-count">181</span></a></li><liclass="ais-HierarchicalMenu-item"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Fans</span><spanclass="ais-HierarchicalMenu-count">91</span></a></li></ul></li><liclass="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent"><aclass="ais-HierarchicalMenu-link"href="#"><spanclass="ais-HierarchicalMenu-label">Audio</span><spanclass="ais-HierarchicalMenu-count">1,570</span></a></li></ul><buttonclass="ais-HierarchicalMenu-showMore ais-HierarchicalMenu-showMore--disabled"disabled>Show more</button></div>
Options
BeforeAfter
attributeNameattribute
showMore.limitshowMoreLimit
showMore.templates.activetemplates.showMoreText
showMore.templates.inactivetemplates.showMoreText
  • showMore is now a boolean option (showMore.templates are now in templates)
  • sortBy defaults to ['isRefined', 'name:asc']
  • An object containing isShowingMore is passed to showMoreText template to toggle between the two states:
1 2 3 4 5 6 7 8 9 10 
{showMoreText:` {{#isShowingMore}} Show less {{/isShowingMore}} {{^isShowingMore}} Show more {{/isShowingMore}} `}
CSS classes
BeforeAfter
ais-menuais-Menu
ais-menu--listais-Menu-list
ais-menu--itemais-Menu-item
ais-menu--item__activeais-Menu-item--selected
ais-menu--linkais-Menu-link
 ais-Menu-label
ais-menu--countais-Menu-count
 ais-Menu-noResults
 ais-Menu-showMore
 ais-Menu-showMore--disabled
Markup
Default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
<divclass="ais-Menu"><ulclass="ais-Menu-list"><liclass="ais-Menu-item ais-Menu-item--selected"><aclass="ais-Menu-link"href="#"><spanclass="ais-Menu-label">Appliances</span><spanclass="ais-Menu-count">4,306</span></a></li><liclass="ais-Menu-item"><aclass="ais-Menu-link"href="#"><spanclass="ais-Menu-label">Audio</span><spanclass="ais-Menu-count">1,570</span></a></li></ul><buttonclass="ais-Menu-showMore">Show more</button></div>
Show more disabled
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
<divclass="ais-Menu"><ulclass="ais-Menu-list"><liclass="ais-Menu-item ais-Menu-item--selected"><aclass="ais-Menu-link"href="#"><spanclass="ais-Menu-label">Appliances</span><spanclass="ais-Menu-count">4,306</span></a></li><liclass="ais-Menu-item"><aclass="ais-Menu-link"href="#"><spanclass="ais-Menu-label">Audio</span><spanclass="ais-Menu-count">1,570</span></a></li></ul><buttonclass="ais-Menu-showMore ais-Menu-showMore--disabled"disabled>Show more</button></div>
Options
BeforeAfter
attributeNameattribute
CSS classes
BeforeAfter
ais-menu-selectais-MenuSelect
 ais-MenuSelect--noRefinement
ais-menu-select--selectais-MenuSelect-select
ais-menu-select--optionais-MenuSelect-option
ais-menu-select--header 
ais-menu-select--footer 
Markup
1 2 3 4 5 6 
<divclass="ais-MenuSelect"><selectclass="ais-MenuSelect-select"><optionclass="ais-MenuSelect-option"value="Appliances">Appliances (4306)</option><optionclass="ais-MenuSelect-option"value="Audio">Audio (1570)</option></select></div>

NumericMenu (formerly NumericRefinementList)

Options
BeforeAfter
attributeNameattribute
optionsitems

The item name attribute is now named label.

CSS classes
BeforeAfter
ais-refinement-listais-NumericMenu
 ais-NumericMenu--noRefinement
ais-refinement-list--listais-NumericMenu-list
ais-refinement-list--itemais-NumericMenu-item
ais-refinement-list--item__activeais-NumericMenu-item--selected
ais-refinement-list--labelais-NumericMenu-label
ais-refinement-list--radioais-NumericMenu-radio
 ais-NumericMenu-labelText
Markup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
<divclass="ais-NumericMenu"><ulclass="ais-NumericMenu-list"><liclass="ais-NumericMenu-item ais-NumericMenu-item--selected"><labelclass="ais-NumericMenu-label"><inputclass="ais-NumericMenu-radio"type="radio"name="NumericMenu"checked=""/><spanclass="ais-NumericMenu-labelText">All</span></label></li><liclass="ais-NumericMenu-item"><labelclass="ais-NumericMenu-label"><inputclass="ais-NumericMenu-radio"type="radio"name="NumericMenu"/><spanclass="ais-NumericMenu-labelText">Less than 500</span></label></li></ul></div>

NumericSelector

Widget removed.

Pagination

Options
BeforeAfter
maxPagestotalPages
showFirstLastshowFirstshowLast
 showNext
 showPrevious
labelstemplates
labels.previoustemplates.previous
labels.nexttemplates.next
labels.firsttemplates.first
labels.lasttemplates.last
CSS classes
BeforeAfter
 ais-Pagination
 ais-Pagination--noRefinement
ais-paginationais-Pagination-list
ais-pagination--itemais-Pagination-item
ais-pagination--item__firstais-Pagination-item--firstPage
ais-pagination--item__lastais-Pagination-item--lastPage
ais-pagination--item__previousais-Pagination-item--previousPage
ais-pagination--item__nextais-Pagination-item--nextPage
 ais-Pagination-item--page
ais-pagination--item__activeais-Pagination-item--selected
ais-pagination--item__disabledais-Pagination-item--disabled
ais-pagination--linkais-Pagination-link
Markup
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 
<divclass="ais-Pagination"><ulclass="ais-Pagination-list"><liclass="ais-Pagination-item ais-Pagination-item--firstPage ais-Pagination-item--disabled"><spanclass="ais-Pagination-link"aria-label="Previous">‹‹</span></li><liclass="ais-Pagination-item ais-Pagination-item--previousPage ais-Pagination-item--disabled"><spanclass="ais-Pagination-link"aria-label="Previous"></span></li><liclass="ais-Pagination-item ais-Pagination-item--selected"><aclass="ais-Pagination-link"href="#">1</a></li><liclass="ais-Pagination-item ais-Pagination-item--page"><aclass="ais-Pagination-link"href="#">2</a></li><liclass="ais-Pagination-item ais-Pagination-item--page"><aclass="ais-Pagination-link"href="#">3</a></li><liclass="ais-Pagination-item"><aclass="ais-Pagination-link"href="#">4</a></li><liclass="ais-Pagination-item ais-Pagination-item--nextPage"><aclass="ais-Pagination-link"aria-label="Next"href="#"></a></li><liclass="ais-Pagination-item ais-Pagination-item--lastPage"><aclass="ais-Pagination-link"aria-label="Next"href="#">››</a></li></ul></div>

PriceRanges

Widget removed.

RangeInput

Options
BeforeAfter
attributeNameattribute
labelstemplates
labels.separatortemplates.separatorText
labels.submittemplates.submitText
CSS classes
BeforeAfter
ais-range-inputais-RangeInput
 ais-RangeInput--noRefinement
ais-range-input--body 
ais-range-input--formais-RangeInput-form
ais-range-input--fieldset 
 ais-RangeInput-label
ais-range-input--labelMin 
ais-range-input--labelMax 
 ais-RangeInput-input
ais-range-input--inputMinais-RangeInput-input--min
ais-range-input--inputMaxais-RangeInput-input--max
ais-range-input--separatorais-RangeInput-separator
ais-range-input--submitais-RangeInput-submit
Markup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
<divclass="ais-RangeInput"><formclass="ais-RangeInput-form"><labelclass="ais-RangeInput-label"><inputclass="ais-RangeInput-input ais-RangeInput-input--min"type="number"/></label><spanclass="ais-RangeInput-separator">to</span><labelclass="ais-RangeInput-label"><inputclass="ais-RangeInput-input ais-RangeInput-input--max"type="number"/></label><buttonclass="ais-RangeInput-submit"type="submit">Go</button></form></div>

RangeSlider

Options
BeforeAfter
attributeNameattribute
CSS classes
BeforeAfter
ais-range-sliderais-RangeSlider
ais-range-slider--disabledais-RangeSlider--disabled
ais-range-slider--handleais-RangeSlider-handle
ais-range-slider--tooltipais-RangeSlider-tooltip
ais-range-slider--valueais-RangeSlider-value
ais-range-slider--marker-horizontalais-RangeSlider-marker--horizontal
ais-range-slider--marker-largeais-RangeSlider-marker--large
Markup
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 48 49 50 51 52 53 
<divclass="ais-RangeSlider"><divclass="rheostat rheostat-horizontal"style="position: relative;"><divclass="rheostat-background"></div><divclass="rheostat-handle rehostat-handle--lower"aria-valuemax="5000"aria-valuemin="1"aria-valuenow="750"aria-disabled="false"data-handle-key="0"role="slider"tabindex="0"style="left: 15%; position: absolute;"><divclass="rheostat-tooltip">$750</div></div><divclass="rheostat-handle rheostat-handle--upper"aria-valuemax="5000"aria-valuemin="750"aria-valuenow="5000"aria-disabled="false"data-handle-key="1"role="slider"tabindex="0"style="left: 100%; position: absolute;"><divclass="rheostat-tooltip">$5,000</div></div><divclass="rheostat-progress"style="left: 15%; width: 85%;"></div><divclass="rheostat-marker rheostat-marker--large"style="left: 0%; position: absolute; margin-left: 0px;"><divclass="rheostat-value">1</div></div><divclass="rheostat-marker"style="left: 2.94118%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 5.88235%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 8.82353%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 11.7647%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 14.7059%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 17.6471%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 20.5882%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 23.5294%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 26.4706%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 29.4118%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 32.3529%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 35.2941%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 38.2353%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 41.1765%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 44.1176%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 47.0588%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker rheostat-marker--large"style="left: 50%; position: absolute; margin-left: 0px;"><divclass="rheostat-value">2,500</div></div><divclass="rheostat-marker"style="left: 52.9412%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 55.8824%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 58.8235%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 61.7647%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 64.7059%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 67.6471%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 70.5882%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 73.5294%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 76.4706%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 79.4118%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 82.3529%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 85.2941%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 88.2353%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 91.1765%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 94.1176%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker"style="left: 97.0588%; position: absolute; margin-left: 0px;"></div><divclass="rheostat-marker rheostat-marker--large"style="left: 100%; position: absolute; margin-left: -1px;"><divclass="rheostat-value">5,000</div></div></div></div>

RatingMenu (formerly StarRating)

Options
BeforeAfter
attributeNameattribute
labels.andUpRemoved

The value for the label andUp is now inline inside templates.item.

CSS classes
BeforeAfter
ais-star-ratingais-RatingMenu
ais-star-rating--listais-RatingMenu-list
ais-star-rating--itemais-RatingMenu-item
ais-star-rating--item__activeais-RatingMenu-item--selected
ais-star-rating--item__disabledais-RatingMenu-item--disabled
ais-star-rating--linkais-RatingMenu-link
ais-star-rating--starais-RatingMenu-starIcon
 ais-RatingMenu-starIcon--full
ais-star-rating--star__emptyais-RatingMenu-starIcon--empty
ais-star-rating--countais-RatingMenu-count
Markup
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 
<divclass="ais-RatingMenu"><svgxmlns="http://www.w3.org/2000/svg"style="display:none;"><symbolid="ais-RatingMenu-starSymbol"viewBox="0 0 24 24"><pathd="M12 .288l2.833 8.718h9.167l-7.417 5.389 2.833 8.718-7.416-5.388-7.417 5.388 2.833-8.718-7.416-5.389h9.167z"/></symbol><symbolid="ais-RatingMenu-starEmptySymbol"viewBox="0 0 24 24"><pathd="M12 6.76l1.379 4.246h4.465l-3.612 2.625 1.379 4.246-3.611-2.625-3.612 2.625 1.379-4.246-3.612-2.625h4.465l1.38-4.246zm0-6.472l-2.833 8.718h-9.167l7.416 5.389-2.833 8.718 7.417-5.388 7.416 5.388-2.833-8.718 7.417-5.389h-9.167l-2.833-8.718z"/></symbol></svg><ulclass="ais-RatingMenu-list"><liclass="ais-RatingMenu-item ais-RatingMenu-item--disabled"><divclass="ais-RatingMenu-link"aria-label="5 & up"disabled><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><spanclass="ais-RatingMenu-label"aria-hidden="true">& Up</span><spanclass="ais-RatingMenu-count">2,300</span></div></li><liclass="ais-RatingMenu-item ais-RatingMenu-item--selected"><aclass="ais-RatingMenu-link"aria-label="4 & up"href="#"><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--empty"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starEmptySymbol"></use></svg><spanclass="ais-RatingMenu-label"aria-hidden="true">& Up</span><spanclass="ais-RatingMenu-count">2,300</span></a></li><liclass="ais-RatingMenu-item"><aclass="ais-RatingMenu-link"aria-label="3 & up"href="#"><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--full"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starSymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--empty"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starEmptySymbol"></use></svg><svgclass="ais-RatingMenu-starIcon ais-RatingMenu-starIcon--empty"aria-hidden="true"width="24"height="24"><usexlink:href="#ais-RatingMenu-starEmptySymbol"></use></svg><spanclass="ais-RatingMenu-label"aria-hidden="true">& Up</span><spanclass="ais-RatingMenu-count">1,750</span></a></li></ul></div>

RefinementList

Options
BeforeAfter
attributeNameattribute
searchForFacetValuessearchable
searchForFacetValues.placeholdersearchablePlaceholder
searchForFacetValues.isAlwaysActivesearchableIsAlwaysActive
searchForFacetValues.escapeFacetValuessearchableEscapeFacetValues
searchForFacetValues.templates.noResultstemplates.searchableNoResults
showMore.templates.activetemplates.showMoreText
showMore.templates.inactivetemplates.showMoreText
  • searchablePlaceholder defaults to "Search..."
  • searchableEscapeFacetValues defaults to true
  • searchableIsAlwaysActive defaults to true
  • showMore is now a boolean option (searchForFacetValues.templates and showMore.templates are now in templates)
  • An object containing isShowingMore is passed to showMoreText template to toggle between the two states:
1 2 3 4 5 6 7 8 9 10 
{showMoreText:` {{#isShowingMore}} Show less {{/isShowingMore}} {{^isShowingMore}} Show more {{/isShowingMore}} `}
CSS classes
BeforeAfter
ais-refinement-listais-RefinementList
 ais-RefinementList--noRefinement
 ais-RefinementList-noResults
ais-refinement-list--header 
ais-refinement-list--body 
ais-refinement-list--footer 
ais-refinement-list--listais-RefinementList-list
ais-refinement-list--itemais-RefinementList-item
ais-refinement-list--item__activeais-RefinementList-item--selected
ais-refinement-list--labelais-RefinementList-label
ais-refinement-list--checkboxais-RefinementList-checkbox
 ais-RefinementList-labelText
ais-refinement-list--countais-RefinementList-count
 ais-RefinementList-showMore
 ais-RefinementList-showMore--disabled
Markup
Default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
<divclass="ais-RefinementList"><divclass="ais-RefinementList-searchBox"><!-- SearchBox widget here --></div><ulclass="ais-RefinementList-list"><liclass="ais-RefinementList-item ais-RefinementList-item--selected"><labelclass="ais-RefinementList-label"><inputclass="ais-RefinementList-checkbox"type="checkbox"value="Insignia™"checked=""/><spanclass="ais-RefinementList-labelText">Insignia™</span><spanclass="ais-RefinementList-count">746</span></label></li><liclass="ais-RefinementList-item"><labelclass="ais-RefinementList-label"><inputclass="ais-RefinementList-checkbox"type="checkbox"value="Samsung"><spanclass="ais-RefinementList-labelText">Samsung</span><spanclass="ais-RefinementList-count">633</span></label></li></ul><buttonclass="ais-RefinementList-showMore">Show more</button></div>
Show more disabled
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
<divclass="ais-RefinementList"><divclass="ais-RefinementList-searchBox"><!-- SearchBox widget here --></div><ulclass="ais-RefinementList-list"><liclass="ais-RefinementList-item ais-RefinementList-item--selected"><labelclass="ais-RefinementList-label"><inputclass="ais-RefinementList-checkbox"type="checkbox"value="Insignia™"checked=""/><spanclass="ais-RefinementList-labelText">Insignia™</span><spanclass="ais-RefinementList-count">746</span></label></li><liclass="ais-RefinementList-item"><labelclass="ais-RefinementList-label"><inputclass="ais-RefinementList-checkbox"type="checkbox"value="Samsung"><spanclass="ais-RefinementList-labelText">Samsung</span><spanclass="ais-RefinementList-count">633</span></label></li></ul><buttonclass="ais-RefinementList-showMore ais-RefinementList-showMore--disabled"disabled>Show more</button></div>
With search and no results
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 
<divclass="ais-RefinementList"><divclass="ais-RefinementList-searchBox"><divclass="ais-SearchBox"><formclass="ais-SearchBox-form"novalidate><inputclass="ais-SearchBox-input"autocomplete="off"autocorrect="off"autocapitalize="off"placeholder="Search for products"spellcheck="false"maxlength="512"type="search"value=""/><buttonclass="ais-SearchBox-submit"type="submit"title="Submit the search query."><svgclass="ais-SearchBox-submitIcon"xmlns="http://www.w3.org/2000/svg"width="10"height="10"viewBox="0 0 40 40"><pathd="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"></path></svg></button><buttonclass="ais-SearchBox-reset"type="reset"title="Clear the search query."hidden><svgclass="ais-SearchBox-resetIcon"xmlns="http://www.w3.org/2000/svg"viewBox="0 0 20 20"width="10"height="10"><pathd="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path></svg></button><spanclass="ais-SearchBox-loadingIndicator"hidden><svgwidth="16"height="16"viewBox="0 0 38 38"xmlns="http://www.w3.org/2000/svg"stroke="#444"class="ais-SearchBox-loadingIcon"><gfill="none"fillRule="evenodd"><gtransform="translate(1 1)"strokeWidth="2"><circlestroke-opacity=".5"cx="18"cy="18"r="18"/><pathd="M36 18c0-9.94-8.06-18-18-18"><animateTransformattributeName="transform"type="rotate"from="0 18 18"to="360 18 18"dur="1s"repeatCount="indefinite"/></path></g></g></svg></span></form></div></div><divclass="ais-RefinementList-noResults">No results.</div></div>
Options
BeforeAfter
poweredByuse the poweredBy widget
wrapInputuse the connectSearchBox connector
searchOnEnterKeyPressOnlysearchAsYouType (default: true)
resetshowReset
magnifiershowSubmit
loadingIndicatorshowLoadingIndicator (default: true)

With the drop of wrapInput, it was decided not to accept inputs as containers anymore. If you want complete control over the rendering, you should use the connectSearchBox connector.

The search box doesn’t support poweredBy. Algolia requires that you use this widget if you’re on a community plan (open source, not-for-profit, or DocSearch).

Configuration options for reset, submit and loadingIndicator have been moved to templates and cssClasses. For example, for reset:

  • reset.template => templates.reset
  • reset.cssClasses.root => cssClasses.reset

autofocus is now set to false by default and doesn’t support the "auto" value anymore.

CSS classes
BeforeAfter
ais-search-boxais-SearchBox
 ais-SearchBox-form
ais-search-box--inputais-SearchBox-input
ais-search-box--magnifier-wrapper 
ais-search-box--magnifierais-SearchBox-submit
 ais-SearchBox-submitIcon
ais-search-box--reset-wrapper 
ais-search-box--resetais-SearchBox-reset
 ais-SearchBox-resetIcon
ais-search-box--loading-indicator-wrapper 
ais-search-box--loading-indicatorais-SearchBox-loadingIndicator
 ais-SearchBox-loadingIcon
Markup
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 
<divclass="ais-SearchBox"><formclass="ais-SearchBox-form"novalidate><inputclass="ais-SearchBox-input"autocomplete="off"autocorrect="off"autocapitalize="off"placeholder="Search for products"spellcheck="false"maxlength="512"type="search"value=""/><buttonclass="ais-SearchBox-submit"type="submit"title="Submit the search query."><svgclass="ais-SearchBox-submitIcon"xmlns="http://www.w3.org/2000/svg"width="10"height="10"viewBox="0 0 40 40"><pathd="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"></path></svg></button><buttonclass="ais-SearchBox-reset"type="reset"title="Clear the search query."hidden><svgclass="ais-SearchBox-resetIcon"xmlns="http://www.w3.org/2000/svg"viewBox="0 0 20 20"width="10"height="10"><pathd="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path></svg></button><spanclass="ais-SearchBox-loadingIndicator"hidden><svgwidth="16"height="16"viewBox="0 0 38 38"xmlns="http://www.w3.org/2000/svg"stroke="#444"class="ais-SearchBox-loadingIcon"><gfill="none"fillRule="evenodd"><gtransform="translate(1 1)"strokeWidth="2"><circlestrokeOpacity=".5"cx="18"cy="18"r="18"/><pathd="M36 18c0-9.94-8.06-18-18-18"><animateTransformattributeName="transform"type="rotate"from="0 18 18"to="360 18 18"dur="1s"repeatCount="indefinite"/></path></g></g></svg></span></form><div>

SortBy

Options
BeforeAfter
indicesitems
  • A sortBy item value is now value instead of name:
1 2 3 4 
constsortByItem={value:string,label:string,};
CSS classes
BeforeAfter
 ais-SortBy
ais-sort-by-selectorais-SortBy-select
ais-sort-by--itemais-SortBy-option
Markup
1 2 3 4 5 6 
<divclass="ais-SortBy"><selectclass="ais-SortBy-select"><optionclass="ais-SortBy-option"value="Most relevant">Most relevant</option><optionclass="ais-SortBy-option"value="Lowest price">Lowest price</option></select></div>

Stats

CSS classes
BeforeAfter
ais-statsais-Stats
ais-stats--body 
ais-stats--time 
 ais-Stats-text
Markup
1 2 3 
<divclass="ais-Stats"><spanclass="ais-Stats-text">20,337 results found in 1ms.</span></div>

ToggleRefinement (formerly Toggle)

Options
BeforeAfter
attributeNameattribute
collapsible 
autoHideContainer 
labeltemplates.labelText
templates.item 
values.onon
values.offoff

collapsible and autoHideContainer options have been removed. These options are now implemented as part of the Panel widget wrapper.

The label options has been moved into the templates.labelText template to make it consistent with the templates parameters of other widgets and the item template was removed. Data that was provided to templates.item is now provided to templates.labelText. If your index attribute is called free_shipping, the default template displays “free_shipping”. To rename it, change templates.labelText to “Free shipping”.

CSS classes
BeforeAfter
ais-toggleais-ToggleRefinement
ais-toggle--list 
ais-toggle--item 
 ais-ToggleRefinement-label
ais-toggle--checkboxais-ToggleRefinement-checkbox
ais-toggle--labelais-ToggleRefinement-labelText
Markup
1 2 3 4 5 6 
<divclass="ais-ToggleRefinement"><labelclass="ais-ToggleRefinement-label"><inputclass="ais-ToggleRefinement-checkbox"type="checkbox"value="Free Shipping"/><spanclass="ais-ToggleRefinement-labelText">Free Shipping</span></label></div>

Connectors

connectAutocomplete

Options
BeforeAfter
escapeHitsescapeHTML
  • escapeHTML becomes true by default.

connectBreadcrumb

  • The BreadcrumbItem name property is renamed to label.

connectGeoSearch

Options
BeforeAfter
paddingBoundingBoxRemoved
enableGeolocationWithIPRemoved - use the Configure widget instead (see below)
positionRemoved - use the Configure widget instead (see below)
radiusRemoved - use the Configure widget instead (see below)
precisionRemoved - use the Configure widget instead (see below)

Since paddingBoundingBox conflicted with the routing option it was removed to support URLSync for the GeoSearch widget.

enableGeolocationWithIP

Before:

1 2 3 4 5 6 7 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});customGeoSearch({enableGeolocationWithIP:true,});

After:

1 2 3 4 5 6 7 8 9 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});instantsearch.widgets.configure({aroundLatLngViaIP:true,});customGeoSearch();
position

Before:

1 2 3 4 5 6 7 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});customGeoSearch({position:{lat:40.71,lng:-74.01},});

After:

1 2 3 4 5 6 7 8 9 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});instantsearch.widgets.configure({aroundLatLng:'40.71, -74.01',});customGeoSearch();
radius

Before:

1 2 3 4 5 6 7 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});customGeoSearch({radius:1000,});

After:

1 2 3 4 5 6 7 8 9 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});instantsearch.widgets.configure({aroundRadius:1000,});customGeoSearch();
precision

Before:

1 2 3 4 5 6 7 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});customGeoSearch({precision:1000,});

After:

1 2 3 4 5 6 7 8 9 
constcustomGeoSearch=instantsearch.connectors.connectGeoSearch(()=>{// Render implementation});instantsearch.widgets.configure({aroundPrecision:1000,});customGeoSearch();

connectRange

Options
BeforeAfter
attributeNameattribute

connectRangeSlider

Connector removed (use connectRange instead).

connectClearRefinements (formerly connectClearAll)

Options
BeforeAfter
excludeAttributesexcludedAttributes

connectNumericMenu (formerly connectNumericRefinementList)

Options
BeforeAfter
attributeNameattribute
optionsitems
  • name becomes label

connectRefinementList

Options
BeforeAfter
attributeNameattribute
  • escapeFacetValues defaults to true

connectCurrentRefinements (used to be connectCurrentRefinedValues)

Options
BeforeAfter
clearsQueryexcludedAttributes: []
items (used to be refinements)

refinements used to be a flat list, now it is called items (one per attribute), which each has its own list of refinements

Upgrade from v1 to v2

This guide has all the major changes that introduced in v2 with the description on how to migrate from v1.

The searchBox widget has new default options

To identify the input as a search box, a magnifying glass icon was placed at the start, and a reset button displayed as a cross at the end.

You can customize the result with these two options:

  • resetboolan|{template?: string|Function, cssClasses?: {root: string}} Display a reset button in the input when there is a query.
  • magnifierboolan|{template?: string|Function, cssClasses?: {root: string}} Display a magnifier should at beginning of the input.

To make the search box like in v1, you can do the following:

1 2 3 4 5 6 7 8 
constsearch=instantsearch(/* Your parameters here */);search.addWidgets([instantsearch.widgets.searchbox({container:'#your-search-input',reset:false,magnifier:false,})]);

You can read more about these options on the searchBox API reference.

No more hitsPerPage in hits and infiniteHits

This option was removed from those two widgets. To configure this option of the engine, there are still three ways:

  • Use the dashboard or the client, to change the setting at the index level.
  • Use the hitsPerPage widget.
  • Use the configuration option of instantsearch:
1 2 3 4 5 6 
constsearch=instantsearch({// ... do not forget the credentialssearchParameters:{hitsPerPage:42,}});

The items aren’t sorted like before in the refinementList / menu

The default sort order of those widgets has changed. This might have affected your implementation if you didn’t specify them originally. To change back the order use the sortBy configuration key.

Here are examples of usage of sortBy using the previous sorting scheme:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
constyourSearch=instantsearch(/* parameters */);yourSearch.addWidgets([instantsearch.widgets.refinementList({container:'#brands',attributeName:'brand',// now the default is ['isRefined', 'count:desc', 'name:asc']sortBy:['count:desc','name:asc'],}),instantsearch.widgets.menu({container:'#categories',attributeName:'categories',// now the default is ['name:asc']sortBy:['count:desc','name:asc']})]);

If you want to learn more about sorting the values, check out the widget API to see what are the valid values for the sortBy option of menu or refinementList

Some variables have been changed

Internally all the widgets are now using the connectors. The aim was to ensure the API was as close to the one offered by react-instantsearch connectors. This then affected the name of some variables in the templates and the API.

Changes in templates:

  • In the item template of the hierarchicalMenu and menu widgets, name becomes label
  • In the item template of the refinementList widget, name becomes value.

Changes in the API:

  • In hitsPerPageSelector, the options was renamed to items.

React components can’t be used as templates

When InstantSearch.js was created it was built using React and it wasn’t known that react-instantsearch would be built. react-instantsearch is now the recommended solution if your app uses React. That’s why support for the React based templates was dropped in this release.

Algolia considers the engine used to build the widgets in InstantSearch.js to be an implementation detail. Since it isn’t exposed anymore, Algolia can change it and use the best solution for each release.

RangeSlider widget is using Rheostat as Slider Component

Slider components are hard to implement and that’s why Algolia relies on an external component for that. Algolia is taking the opportunity of this new version to switch to the current ‘state of the art’ of sliders: Rheostat.

If you want to customize the style, some CSS classes have changed. See some examples of style sheets.

The look is still similar as the one in the V1.

searchFunction can be used to change parameters

Introduced in 1.3.0, searchFunction was originally meant as a way to change the timing of the search. However it was realized that it was a good way to alter the search state before making the actual state.

This is what’s required to force the query string:

1 2 3 4 5 6 7 
constsearch=instantsearch({/* other parameters */searchFunction(helper){search.helper.setQuery('fixed query');helper.search();}});

And now, it’s more straightforward:

1 2 3 4 5 6 
constsearch=instantsearch({/* other parameters */searchFunction(helper){helper.setQuery('fixed query').search();}});

Bear in mind that the helper still resets the page to 0 when the parameters change. To keep the previously set page you have to do the following:

1 2 3 4 5 6 7 8 9 
constsearch=instantsearch({/* other parameters */searchFunction(helper){constp=helper.getPage();helper.setQuery('fixed query').setPage(p).search();}});
Did you find this page helpful?
close