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.For more information, see:
You can interpolate dynamic values using template literals placeholders.All available dynamic values are exposed within the scope of the template function.
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.
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.
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:
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.
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):If you’re using a package manager, you can upgrade it to the latest version.
Report incorrect code
Copy
npm install search-insights
Now you can pass the reference to the insights option.
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:
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.
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.
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.
JavaScript
Report incorrect code
Copy
import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';// Or, use `instantsearch.middlewares.createInsightsMiddleware()`const indexName = '<your-index-name>';const search = instantsearch({ indexName, // ...});const insightsMiddleware = createInsightsMiddleware({ insightsClient: window.aa, onEvent: (event, aa) => { const { insightsMethod, payload, widgetType, eventType } = event; // Send the event to Algolia aa(insightsMethod, payload); // Send click events on Hits to a third-party tracker if (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.
JavaScript
Report incorrect code
Copy
const indexName = '<your-index-name>';const search = instantsearch({ indexName, // ...});const analyticsMiddleware = () => { return { onStateChange({ uiState }) { // Google Analytics (Universal Analytics) window.ga('set', 'page', window.location.pathname + window.location.search); window.ga('send', 'pageView'); // Google Analytics V4 gtag('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.
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:
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:
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:
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.
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.
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:
JavaScript
Report incorrect code
Copy
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' }),]);
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.
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.
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.
TypeScript
Report incorrect code
Copy
interface Router { // ... // Before dispose?({ helper, state }: { helper: AlgoliaSearchHelper, state: SearchParameters }): SearchParameters | void // After dispose(): void}
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.
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.
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, or InstantSearch.js.
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.
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.
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.
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.For more information, see:
allItems template has been removed in favor of connectHits
CSS classes
Before
After
ais-hits
ais-Hits
ais-hits--empty
ais-Hits--empty
ais-Hits--list
ais-hits--item
ais-Hits--item
Markup
HTML
Report incorrect code
Copy
<div class="ais-Hits"> <ol class="ais-Hits-list"> <li class="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-Hits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-Hits-item"> Hit 4397400: Google - Chromecast - Black </li> </ol></div>
<div class="ais-InfiniteHits"> <ol class="ais-InfiniteHits-list"> <li class="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li> <li class="ais-InfiniteHits-item"> Hit 5477500: Amazon - Fire TV Stick with Alexa Voice Remote - Black </li> <li class="ais-InfiniteHits-item"> Hit 4397400: Google - Chromecast - Black </li> </ol> <button class="ais-InfiniteHits-loadMore">Show more results</button></div>
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.
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”.
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:
JavaScript
Report incorrect code
Copy
const search = 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.
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:
JavaScript
Report incorrect code
Copy
const yourSearch = 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
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.
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.
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: