UNPKG

@meilisearch/instant-meilisearch

Version:
1,179 lines (895 loc) β€’ 58 kB
<p align="center"> <img src="https://raw.githubusercontent.com/meilisearch/integration-guides/main/assets/logos/logo.svg" alt="Instant-Meilisearch" width="200" height="200" /> </p> <h1 align="center">Instant Meilisearch</h1> <h4 align="center"> <a href="https://github.com/meilisearch/meilisearch">Meilisearch</a> | <a href="https://www.meilisearch.com/docs">Documentation</a> | <a href="https://www.meilisearch.com/pricing?utm_campaign=oss&utm_source=integration&utm_medium=meilisearch-js-plugins">Meilisearch Cloud</a> | <a href="https://discord.meilisearch.com">Discord</a> | <a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> | <a href="https://www.meilisearch.com">Website</a> | <a href="https://www.meilisearch.com/docs/faq">FAQ</a> </h4> <p align="center"> <a href="https://www.npmjs.com/package/@meilisearch/instant-meilisearch"><img src="https://img.shields.io/npm/v/@meilisearch/instant-meilisearch.svg" alt="npm version"></a> <a href="https://github.com/meilisearch/meilisearch-js-plugins/actions"><img src="https://github.com/meilisearch/meilisearch-js-plugins/workflows/Tests/badge.svg?branch=main" alt="Tests"></a> <a href="https://github.com/meilisearch/meilisearch-js-plugins/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a> <a href="https://github.com/meilisearch/meilisearch/discussions" alt="Discussions"><img src="https://img.shields.io/badge/github-discussions-red" /></a> </p> <p align="center">⚑ How to integrate a front-end search bar in your website using Meilisearch</p> **Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch) This library is the search client that you should use to make [Meilisearch](https://github.com/meilisearch/meilisearch) work with [InstantSearch](https://github.com/algolia/instantsearch.js). InstantSearch, an open-source project developed by Algolia, is the tool that renders all the components needed to start searching in your front-end application. Instead of reinventing the wheel, we have opted to reuse the InstantSearch library for our own front-end tooling. We will contribute upstream any improvements that may result from our adoption of InstantSearch. If you use Angular, React, or Vue, you might want to check out these repositories: - [meilisearch-angular](https://github.com/meilisearch/meilisearch-angular/) - [meilisearch-react](https://github.com/meilisearch/meilisearch-react/) - [meilisearch-vue](https://github.com/meilisearch/meilisearch-vue/) NB: If you don't have any Meilisearch instance running and containing your data, you should take a look at this [getting started page](https://www.meilisearch.com/docs/learn/getting_started/installation). ## Table of Contents <!-- omit in toc --> - [πŸ“– Documentation](#-documentation) - [⚑ Supercharge your Meilisearch experience](#-supercharge-your-meilisearch-experience) - [πŸ”§ Installation](#-installation) - [🎬 Usage](#-usage) - [Basic](#basic) - [Parameters](#parameters) - [πŸ’… Customization](#-customization) - [Placeholder Search](#placeholder-search) - [Finite Pagination](#finite-pagination) - [Primary key](#primary-key) - [Keep zero facets](#keep-zero-facets) - [Request Config](#request-config) - [Custom HTTP client](#custom-http-client) - [Meilisearch Analytics](#meilisearch-analytics) - [Meilisearch search parameters](#meilisearch-search-parameters) - [Modify Meilisearch search parameters](#modify-meilisearch-search-parameters) - [πŸͺ‘ Example with InstantSearch](#-example-with-instantsearch) - [More Documentation](#more-documentation) - [πŸ€– Compatibility with Meilisearch and InstantSearch](#-compatibility-with-meilisearch-and-instantsearch) - [πŸ“œ API resources](#-api-resources) - [Table Of Widgets](#table-of-widgets) - [βœ… InstantSearch](#-instantsearch) - [βœ… Index](#-index) - [βœ… SearchBox](#-searchbox) - [βœ… Configure](#-configure) - [❌ ConfigureRelatedItems](#-configurerelateditems) - [Panel](#panel) - [❌ Autocomplete](#-autocomplete) - [βœ… Voice Search](#-voice-search) - [βœ… Insight](#-insight) - [βœ… Middleware](#-middleware) - [βœ… renderState](#-renderstate) - [βœ… Hits](#-hits) - [βœ… InfiniteHits](#-infinitehits) - [βœ… Highlight](#-highlight) - [βœ… Snippet](#-snippet) - [βœ… Geo Search](#-geo-search) - [Requirements](#requirements) - [Usage](#usage) - [❌ Answers](#-answers) - [βœ… RefinementList](#-refinementlist) - [βœ… HierarchicalMenu](#-hierarchicalmenu) - [Hierarchical Menu Usage](#hierarchical-menu-usage) - [βœ… RangeSlider](#-rangeslider) - [βœ… Menu](#-menu) - [βœ… currentRefinements](#-currentrefinements) - [βœ… RangeInput](#-rangeinput) - [βœ… MenuSelect](#-menuselect) - [βœ… ToggleRefinement](#-togglerefinement) - [βœ… NumericMenu](#-numericmenu) - [βœ… RatingMenu](#-ratingmenu) - [βœ… ClearRefinements](#-clearrefinements) - [βœ… Pagination](#-pagination) - [βœ… HitsPerPage](#-hitsperpage) - [βœ… Breadcrumb](#-breadcrumb) - [βœ… Stats](#-stats) - [❌ Analytics](#-analytics) - [❌ QueryRuleCustomData](#-queryrulecustomdata) - [❌ QueryRuleContext](#-queryrulecontext) - [βœ… SortBy](#-sortby) - [Sort formula](#sort-formula) - [Relevancy](#relevancy) - [Example](#example) - [❌ RelevantSort](#-relevantsort) - [βœ… Routing](#-routing) - [βš™οΈ Development Workflow and Contributing](#️-development-workflow-and-contributing) ## πŸ“– Documentation For general information on how to use Meilisearchβ€”such as our API reference, tutorials, guides, and in-depth articlesβ€”refer to our [main documentation website](https://www.meilisearch.com/docs/). ## ⚑ Supercharge your Meilisearch experience Say goodbye to server deployment and manual updates with [Meilisearch Cloud](https://www.meilisearch.com/pricing?utm_campaign=oss&utm_source=integration&utm_medium=meilisearch-js-plugins). No credit card required. ## πŸ”§ Installation Use `npm` or `pnpm` to install `instant-meilisearch`: ```bash npm install @meilisearch/instant-meilisearch ``` ```bash pnpm add @meilisearch/instant-meilisearch ``` `instant-meilisearch` is a client for `instantsearch.js`. It does not create any UI component by itself.<br> To be able to create a search interface, you'll need to [install `instantsearch.js`](https://www.algolia.com/doc/guides/building-search-ui/installation/js/) as well. ## 🎬 Usage ### Basic ```js import { instantMeiliSearch } from '@meilisearch/instant-meilisearch' const { searchClient, setMeiliSearchParams } = instantMeiliSearch( 'https://ms-adf78ae33284-106.lon.meilisearch.io', // Host 'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303' // API key ) ``` where `searchClient` is to be passed to instantsearch.js or its many framework adaptations, and [`setMeiliSearchParams`](#modify-meilisearch-search-parameters) is a function used to set/modify certain Meilisearch search parameters to be overridden. ### Parameters - `Host` - URL of Meilisearch instance - `API Key` - Meilisearch access API Key. This can either be a string or a synchronous function that returns a string. ⚠️ Prefer using a key with only [search permissions](https://www.meilisearch.com/docs/learn/security/master_api_keys#master-key-and-api-keys) as it is used on your front-end. ## πŸ’… Customization `instant-meilisearch` offers some options you can set to further fit your needs. - [`placeholderSearch`](#placeholder-search): Enable or disable placeholder search (default: `true`). - [`finitePagination`](#finite-pagination): Enable finite pagination when using the [`pagination`](#-pagination) widget (default: `false`) . - [`primaryKey`](#primary-key): Specify the primary key of your documents (default `undefined`). - [`keepZeroFacets`](#keep-zero-facets): Show the facets value even when they have 0 matches (default `false`). - [`requestInit`](#request-config): Use custom request configurations. - [`httpClient`](#custom-http-client): Use a custom HTTP client. - [`meiliSearchParams`](#meilisearch-search-parameters): Override a selection of Meilisearch search parameters (default `undefined`). The options are added as the third parameter of the `instantMeilisearch` function. ```js import { instantMeiliSearch } from '@meilisearch/instant-meilisearch' const { searchClient } = instantMeiliSearch( 'https://ms-adf78ae33284-106.lon.meilisearch.io', 'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303', { placeholderSearch: false, // default: true. primaryKey: 'id', // default: undefined // ... } ) ``` ### Placeholder Search Placeholders search means showing results even when the search query is empty. By default it is `true`. When placeholder search is set to `false`, no results appears when searching on no characters. For example, if the query is "" no results appear. ```js { placeholderSearch : true } // default true ``` ### Finite Pagination Finite pagination is used when you want to add a numbered pagination at the bottom of your hits (for example: `<< < 1, 2, 3 > >>`). It requires the usage of the [`Pagination` widget](#-pagination). Example: ```js { finitePagination: true } // default: false ``` ### Primary key Specify the field in your documents containing the [unique identifier](https://www.meilisearch.com/docs/learn/core_concepts/documents#primary-field) (`undefined` by default). By adding this option, we avoid instantSearch errors that are thrown in the browser console. In `React` particularly, this option removes the `Each child in a list should have a unique "key" prop` error. ```js { primaryKey : 'id' } // default: undefined ``` ### Keep zero facets `keepZeroFacets` set to `true` keeps the facets even when they have 0 matching documents (default `false`). When using `refinementList` it happens that by checking some facets, the ones with no more valid documents disapear. Nonetheless you might want to still showcase them even if they have 0 matched documents with the current request: Without `keepZeroFacets` set to `true`: genres: - [x] horror (2000) - [x] thriller (214) - [ ] comedy (0) With `keepZeroFacets` set to `false`, `comedy` disapears: genres: - [x] horror (2000) - [x] thriller (214) ```js { keepZeroFacets : true } // default: false ``` ### Request Config You can provide a custom request configuration. Available field can be [found here](https://fetch.spec.whatwg.org/#requestinit). for example, with custom headers. ```ts { requestInit: { headers: { Authorization: AUTH_TOKEN }, credentials: 'include' } } ``` ### Custom HTTP client You can use your own HTTP client, for example, with [`axios`](https://github.com/axios/axios). ```ts { httpClient: async (url, opts) => { const response = await $axios.request({ url, data: opts?.body, headers: opts?.headers, method: (opts?.method?.toLocaleUpperCase() as Method) ?? 'GET' }) return response.data } } ``` ### Meilisearch Analytics > [!NOTE] > [Search metadata](https://www.meilisearch.com/docs/reference/api/overview?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#search-metadata) is enabled by default on [Meilisearch Cloud](https://www.meilisearch.com/cloud?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch). Search metadata is useful for interacting with the [Meilisearch Analytics Events](https://www.meilisearch.com/docs/learn/analytics/events_endpoint). #### Usage The search client returns `MeilisearchSearchResponse` which extends the standard `AlgoliaSearchResponse` with an optional `_meilisearch` namespace containing metadata: ```ts import { instantMeiliSearch, getAnalyticsMetadata } from '@meilisearch/instant-meilisearch' import instantsearch from 'instantsearch.js' const { searchClient } = instantMeiliSearch( 'https://ms-adf78ae33284-106.lon.meilisearch.io', 'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303' ) const search = instantsearch({ indexName: 'movies', searchClient, }) // Access metadata from results using the helper utility search.on('render', () => { const results = search.helper?.lastResults // Get metadata for a specific index const metadata = getAnalyticsMetadata(results, { indexUid: 'movies' }) if (metadata) { console.log('Query UID:', metadata.queryUid) // UUID v7 identifying the query console.log('Index UID:', metadata.indexUid) console.log('Primary key:', metadata.primaryKey) } }) ``` You can also access metadata directly from the raw results: ```ts search.on('render', () => { const results = search.helper?.lastResults if (results?._rawResults?.[0]?._meilisearch?.metadata) { const { queryUid, indexUid, primaryKey } = results._rawResults[0]._meilisearch.metadata console.log('Query UID:', queryUid) console.log('Index UID:', indexUid) console.log('Primary key:', primaryKey) } }) ``` #### Using metadata for analytics events Each hit includes a `__position` field that you can use for click events: ```ts import { connectHits } from 'instantsearch.js/es/connectors' import { getAnalyticsMetadata } from '@meilisearch/instant-meilisearch' const renderHits = (renderOptions) => { const { hits, results } = renderOptions // Get metadata for sending analytics events const metadata = getAnalyticsMetadata(results, { indexUid: 'movies' }) document.querySelector('#hits').innerHTML = hits .map((hit) => ` <article> <h2>${hit.title}</h2> <button onclick="sendClickEvent('${hit.objectID}', ${hit.__position})"> View Details </button> </article> `) .join('') window.sendClickEvent = (objectId, position) => { if (metadata) { fetch('/events', { method: 'POST', body: JSON.stringify({ eventType: 'click', queryUid: metadata.queryUid, indexUid: metadata.indexUid, objectId: objectId, position: position }) }) } } } connectHits(renderHits) ``` #### Self-hosted instances For self-hosted Meilisearch instances, you need to enable search metadata by setting the `Meili-Include-Metadata` header: ```ts const { searchClient } = instantMeiliSearch( 'http://localhost:7700', 'your-api-key', { requestInit: { headers: { 'Meili-Include-Metadata': 'true' } } } ) ``` ### Meilisearch search parameters `meiliSearchParams` lets you override a set of search parameters that are sent off to Meilisearch. The following options can be overridden: - [`attributesToCrop`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#attributes-to-crop) - [`attributesToHighlight`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#attributes-to-highlight) - [`attributesToRetrieve`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#attributes-to-retrieve) - [`attributesToSearchOn`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#customize-attributes-to-search-on-at-search-time) - [`cropLength`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#crop-length) - [`cropMarker`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#crop-marker) - [`distinct`](https://www.meilisearch.com/docs/learn/relevancy/distinct_attribute) - [`highlightPreTag`, `highlightPostTag`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#highlight-tags) - [`hybrid`](https://www.meilisearch.com/docs/learn/experimental/vector_search) - [`matchingStrategy`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#matching-strategy) - [`showMatchesPosition`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#show-matches-position) - [`showRankingScore`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#ranking-score) - [`rankingScoreThreshold`](https://www.meilisearch.com/docs/reference/api/search?utm_campaign=oss&utm_source=github&utm_medium=instant-meilisearch#ranking-score-threshold) ```js instantMeiliSearch( // ... { meiliSearchParams: { attributesToHighlight: ['overview'], highlightPreTag: '<em>', highlightPostTag: '</em>', attributesToSearchOn: ['overview'], }, } ) ``` When using multi search, meilisearchParams can be overriden for specific indexes : ```js instantMeiliSearch( // ... { meiliSearchParams: { // All indexes will highlight overview attributesToHighlight: ['overview'], highlightPreTag: '<em>', highlightPostTag: '</em>', attributesToSearchOn: ['overview'], indexesOverrides: { movies: { // Only title will be highlighted for hits in movies attributesToHighlight: ['title'] } } }, } ) ``` ### Modify Meilisearch search parameters `instantMeiliSearch` returns an instance with two properties on it, one of them being `setMeiliSearchParams`. ```js const { searchClient, setMeiliSearchParams } = instantMeiliSearch(/*...*/) ``` It modifies (or sets if not already set) the [overridden Meilisearch search parameters](#meilisearch-search-parameters). It only modifies parameters that are defined on the provided object, the following will not change `attributesToHighlight`. ```js const { setMeiliSearchParams } = instantMeiliSearch( // ... { meiliSearchParams: { attributesToHighlight: ['overview'], highlightPreTag: '<em>', highlightPostTag: '</em>', attributesToSearchOn: ['overview'], }, } ) setMeiliSearchParams({ highlightPreTag: '<mark>', highlightPostTag: '</mark>', attributesToSearchOn: ['overview', 'title'], }) ``` ## πŸͺ‘ Example with InstantSearch The open-source [InstantSearch](https://www.algolia.com/doc/api-reference/widgets/js/) library powered by Algolia provides all the front-end tools you need to highly customize your search bar environment. InstantSearch requires that you provide an indexName. The indexName corresponds to the [index `uid`](https://www.meilisearch.com/docs/learn/core_concepts/indexes#indexes) in which your document are stored in Meilisearch. In `index.html`: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> </head> <body> <div> <div id="searchbox"></div> <div id="hits"></div> </div> <script src="https://cdn.jsdelivr.net/npm/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script> <script src="./app.js"></script> </body> </html> ``` In `app.js`: ```js const { searchClient } = instantMeiliSearch( 'https://ms-adf78ae33284-106.lon.meilisearch.io', 'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303' ) const search = instantsearch({ indexName: 'steam-video-games', searchClient, }) search.addWidgets([ instantsearch.widgets.searchBox({ container: '#searchbox', }), instantsearch.widgets.hits({ container: '#hits', templates: { item: ` <div> <div class="hit-name"> {{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}} </div> </div> `, }, }), ]) search.start() ``` πŸš€ For a full getting started example, please take a look at this CodeSandbox: [![Edit MS + IS](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/ms-is-mese9?fontsize=14&hidenavigation=1&theme=dark) πŸ’‘ If you have never used InstantSearch, we recommend reading this [getting started documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/). ## More Documentation - The open-source InstantSearch library is widely used and well documented in the [Algolia documentation](https://www.algolia.com/doc/api-reference/widgets/js/). It provides all the widgets to customize and improve your search bar environment in your website. - The [Meilisearch documentation](https://www.meilisearch.com/docs/). - If you use React, check out [meilisearch-react](https://github.com/meilisearch/meilisearch-react/) - If you use Vue, check out [meilisearch-vue](https://github.com/meilisearch/meilisearch-vue/) - If you use Angular, check out [meilisearch-angular](https://github.com/meilisearch/meilisearch-angular/) ## πŸ€– Compatibility with Meilisearch and InstantSearch **Supported InstantSearch.js versions**: This package only guarantees the compatibility with the [version v4 of InstantSearch.js](https://github.com/algolia/instantsearch.js/releases/tag/v4.24.1). It may work with older or newer InstantSearch versions, but these are not tested nor officially supported at this time. **Supported Meilisearch versions**: This package guarantees compatibility with [version v1.x of Meilisearch](https://github.com/meilisearch/meilisearch/releases/latest), but some features may not be present. Please check the [issues](https://github.com/meilisearch/instant-meilisearch/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+label%3Aenhancement) for more info. **Node / NPM versions**: - NodeJS >= 12.10 <= 18 - NPM >= 6.x ## πŸ“œ API resources List of all the components that are available in [instantSearch](https://github.com/algolia/instantsearch.js) and their compatibility with [Meilisearch](https://github.com/meilisearch/meilisearch/). ### Table Of Widgets - βœ… [InstantSearch](#-instantsearch) - βœ… [index](#-index) - βœ… [SearchBox](#-searchbox) - βœ… [Configure](#-configure) - ❌ [ConfigureRelatedItems](#-configure-related-items) - ❌ [Autocomplete](#-autocomplete) - βœ… [Voice Search](#-voice-search) - βœ… [Insight](#-insight) - βœ… [Middleware](#-middleware) - βœ… [RenderState](#-renderstate) - βœ… [Hits](#-hits) - βœ… [InfiniteHits](#-infinitehits) - βœ… [Highlight](#-highlight) - βœ… [Snippet](#-snippet) - βœ… [Geo Search](#-geo-search) - ❌ [Answers](#-answers) - βœ… [RefinementList](#-refinementlist) - βœ… [HierarchicalMenu](#-hierarchicalmenu) - βœ… [RangeSlider](#-rangeslider) - βœ… [Menu](#-menu) - βœ… [currentRefinements](#-currentrefinements) - βœ… [RangeInput](#-rangeinput) - βœ… [MenuSelect](#-menuselect) - βœ… [ToggleRefinement](#-togglerefinement) - βœ… [NumericMenu](#-numericmenu) - βœ… [RatingMenu](#-ratingmenu) - βœ… [ClearRefinements](#-clearrefinements) - βœ… [Pagination](#-pagination) - βœ… [HitsPerPage](#-hitsperpage) - βœ… [Breadcrumb](#-breadcrumb) - βœ… [Stats](#-stats) - ❌ [Analytics](#-analytics) - ❌ [QueryRuleCustomData](#-queryrulecustomdata) - ❌ [QueryRuleContext](#-queryrulecontext) - βœ… [SortBy](#-sortby) - ❌ [RelevantSort](#-relevantsort) - βœ… [Routing](#-routing) ### βœ… InstantSearch [instantSearch references](https://www.algolia.com/doc/api-reference/widgets/instantsearch/js/) `instantSearch` is the main component. It manages the widget and lets you add new ones. - βœ… IndexName: [`uid` of your index](https://www.meilisearch.com/docs/learn/core_concepts/indexes#indexes). _required_ - βœ… SearchClient: Search client, in our case instant-meilisearch. See [customization](#-customization) for details on options. _required_ - ❌ numberLocale: Does not work with both Algoliasearch and instant-meilisearch. - βœ… searchFunction: Surcharge the search function provided by the search client. - βœ… initialUiState: Determine the search state on app start. - βœ… onStateChange: Change search state on change (see option above). - βœ… stalledSearchDelay: Time in ms before search is considered stalled. [Used for loader](https://www.algolia.com/doc/guides/building-search-ui/going-further/improve-performance/js/#using-the-searchbox). - βœ… routing: browser URL synchronization, search parameters appear in current URL ([guide](https://www.algolia.com/doc/guides/building-search-ui/going-further/routing-urls/js/)). - βœ… insightsClient: Hook analytics to search actions ([see insight section](#-insight)). ```js const search = instantsearch({ indexName: 'instant_search', searchClient: instantMeiliSearch( 'https://ms-adf78ae33284-106.lon.meilisearch.io', 'a63da4928426f12639e19d62886f621130f3fa9ff3c7534c5d179f0f51c4f303', { // ... InstantMeiliSearch options } ).searchClient, // ... InstantSearch options routing: true // for example }) ``` ### βœ… Index [Index references](https://www.algolia.com/doc/api-reference/widgets/index-widget/js/) `Index` is the component that lets you apply widgets to a dedicated index. It’s useful if you want to build an interface that targets multiple indices. ### βœ… SearchBox [SearchBox references](https://www.algolia.com/doc/api-reference/widgets/search-box/js/) The `searchBox` widget is used to let the user perform a text-based query. - βœ… container: The CSS Selector or HTMLElement to insert the widget into. _required_ - βœ… placeholder: Placeholder of the search box. - βœ… autofocus: Whether the search box is focused on arrival. - βœ… searchAsYouType: Whether result appears as you type or after pressing enter. - ❌ showReset: Does not work with both algoliasearch and instant-meilisearch - ❌ showSubmit: Does not work with both algoliasearch and instant-meilisearch - βœ… showLoadingIndicator: Whether to show the spinning loader. - βœ… queryHook: A function that is called just before the search is triggered. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. ```js instantsearch.widgets.searchBox({ container: '#searchbox', autofocus: true, ...searchBoxOptions }), ``` ### βœ… Configure - [Configure references](https://www.algolia.com/doc/api-reference/widgets/configure/js/): See #389 The `configure` widget lets you provide raw search parameters to the Algolia API without rendering anything. Because these are the search parameters of AlgoliaSearch and not the InstantSearch parameters, some of them are ignored by InstantSearch.<br> Since we do not act as AlgoliaSearch on search parameters, detailed compatibility can be found in [this issue](https://github.com/meilisearch/meilisearch-js-plugins/issues/389).<br> This component should only be used if no other component provides the same configuration. We also suggest looking at [Meilisearch's search parameters](https://www.meilisearch.com/docs/reference/api/search#search-parameters) to determine how they act. ```js instantsearch.widgets.configure({ hitsPerPage: 20, // other algoliasearch parameters }) ``` ### ❌ ConfigureRelatedItems [ConfigureRelatedItems references](https://www.algolia.com/doc/api-reference/widgets/configure-related-items/js/). No compatibility with Meilisearch because the component uses [sumOrFiltersScores](https://www.algolia.com/doc/api-reference/api-parameters/sumOrFiltersScores/) and [optionalFilters](https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/) search parameters that do not exist in Meilisearch. ### Panel [Panel references](https://www.algolia.com/doc/api-reference/widgets/panel/js/) The `panel` widget wraps other widgets in a consistent panel design. - βœ… hidden: Function to determine if pannel should be hidden on earch render. - βœ… collapsed: Function to determine if pannel should be collapsed on earch render. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. ### ❌ Autocomplete [Autocomplete references](https://www.algolia.com/doc/api-reference/widgets/autocomplete/js/) Deprecated component in InstantSearch in favor of [autocomplete package](https://github.com/algolia/autocomplete). InstantMeilisearch is not compatible with the autocomplete package. ### βœ… Voice Search [Voice Search references](https://www.algolia.com/doc/api-reference/widgets/voice-search/js/) The `voiceSearch` widget lets the user perform a voice-based query. ### βœ… Insight [Insight references](https://www.algolia.com/doc/api-reference/widgets/insights/js/) Search Insights lets you report click, conversion and view metrics. More details about the subject are [given in this issue](https://github.com/meilisearch/meilisearch-js-plugins/issues/410). Requires InstantSearch v4.8.3 or later. - βœ… insightsClient: Insight client uses [search-insight.js](https://github.com/algolia/search-insights.js). - βœ… insightsInitParams: Insight params. - βœ… onEvent?: function triggered on events. ### βœ… Middleware [Middleware references](https://www.algolia.com/doc/api-reference/widgets/middleware/js/) Middleware is a function returning an object with `onStateChange`, `subscribe` and `unsubscribe` functions. With the middleware API, you can inject functionalities in the InstantSearch lifecycle. ### βœ… renderState [renderState references](https://www.algolia.com/doc/api-reference/widgets/render-state/js/#examples) Provides all the data and functions from the widgets. It works only on widgets that are compatible with `instant-meilisearch`. ### βœ… Hits [hits references](https://www.algolia.com/doc/api-reference/widgets/hits/js/) Used to display a list of results. - βœ… container: The CSS Selector or HTMLElement to insert the hits into. _required_ - βœ… escapeHTML: Escapes HTML tags in string values in returned hits. - βœ… transformItems: Function that maps over every hit the provided logic. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. ```js instantsearch.widgets.hits({ container: '#hits', templates: { item: ` <div> <div class="hit-name"> {{#helpers.highlight}}{ "attribute": "title" }{{/helpers.highlight}} </div> </div> `, }, }) ``` ### βœ… InfiniteHits [infiniteHits references](https://www.algolia.com/doc/api-reference/widgets/infinite-hits/js/) The `infiniteHits` widget is used to display a list of results with a β€œShow more” button. - βœ… container: The CSS Selector or HTMLElement to insert the hits into. _required_ - βœ… escapeHTML: Escapes HTML tags in string values in returned hits. - βœ… transformItems: Function that maps over every hit the provided logic. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. - ❌ showPrevious: Does not work with both Algoliasearch and InstantMeilisearch. - ❌ cache: Not added in InstantMeilisearch. ```js instantsearch.widgets.infiniteHits({ container: '#infinite-hits', templates: { item: ` <h2> {{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}} </h2> `, }, }) ``` ### βœ… Highlight [highlight references](https://www.algolia.com/doc/api-reference/widgets/highlight/js/) The `highlight` function returns an attribute from a hit into its highlighted form, when relevant. - βœ… attribute: The attribute of the record to highlight. _required_ - βœ… hit: Hit object. _required_ - βœ… highlightedTagName: HTML element to wrap the highlighted parts of the string. See [Hits](#-hits) for an example. ### βœ… Snippet [Snippet references](https://www.algolia.com/doc/api-reference/widgets/snippet/js/) The `snippet` function returns an attribute from a hit into its snippet form, when relevant. - βœ… attribute: The attribute of the record to snippet and highlight. _required_ - βœ… hit: Hit object. _required_ - βœ… highlightedTagName: HTML element to wrap the highlighted parts of the string. Note that the attribute has to be added to `attributesToSnippet` in [configuration](#-configure). Highlight is applied on snippeted fields. Snippeting is called `cropping` in Meilisearch, [more about it here](https://www.meilisearch.com/docs/reference/api/search#attributes-to-retrieve). It is possible to change the size of the snippeting by adding its character size in the attributesToSnippet parameter. <br> For example: `"description:40"`. The `40` value represents the number of characters (rounded down to always have full words) and not the number of words. Thus, the snippet string size is always equal to or lower than `40` characters. ```js instantsearch.widgets.configure({ attributesToSnippet: ['description:40'], }) ``` ```js instantsearch.widgets.hits({ // ... templates: { item: ` <p>{{#helpers.snippet}}{ "attribute": "description" }{{/helpers.snippet}}</p> `, }, }) ``` ### βœ… Geo Search [Geo search references](https://www.algolia.com/doc/api-reference/widgets/geo-search/js/) The `geoSearch` widget displays search results on a Google Map. It lets you search for results based on their position and provides some common usage patterns such as β€œsearch on map interactions”. - βœ… container: The CSS Selector or HTMLElement to insert the Google maps into. _required_ - βœ… googleReference: The reference to the global window.google object. See the [Google Maps](https://developers.google.com/maps/documentation/javascript/overview) documentation for more information. _required_ - βœ… initialZoom: When no search results are found, google map will default to this zoom. - βœ… initialPosition: When no search results are found, google map will default to this position. - βœ… mapOptions: The options forwarded to the Google Maps constructor. - ❔ builtInMarker: Used to customize Google Maps markers. Because of lack of tests we cannot guarantee its compatibility. For more information please visit [InstantSearch related documentation](https://www.algolia.com/doc/api-reference/widgets/geo-search/js/#widget-param-builtinmarker). - customHTMLMarker: Same as `builtInMarker`. Because of lack of tests, we cannot guarantee its compatibility. For more information please visit [InstantSearch related documentation](https://www.algolia.com/doc/api-reference/widgets/geo-search/js/#widget-param-customhtmlmarker). - βœ… enableRefine: If true, the map is used for refining the search. Otherwise, it’s only for display purposes. - βœ… enableClearMapRefinement: If `true`, a button is displayed on the map when the refinement is coming from interacting with it, to remove it. - βœ… enableRefineControl: If `true`, the map is used for refining the search. Otherwise, it’s only for display purposes. - βœ… enableRefineOnMapMove: If `true`, a button is displayed on the map when the refinement is coming from interacting with it, to remove it., - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. Check out our [geosearch demo](https://github.com/meilisearch/demos/tree/main/src/geo-javascript) for a working example. #### Requirements The Geosearch widget only works with a valid Google API key. The example below uses the `@googlemaps/js-api-loader` package to load the Google Maps library before initializing `instantSearch`: ```js import { setOptions, importLibrary } from '@googlemaps/js-api-loader' const GOOGLE_MAP_API_KEY = 'YOUR_GOOGLE_MAPS_API_KEY' setOptions({ apiKey: GOOGLE_MAP_API_KEY, version: 'weekly', }) importLibrary('maps').then(() => { const search = instantsearch({ indexName: 'geo', // ... }) // ... }) ``` Replace `YOUR_GOOGLE_MAPS_API_KEY` with your Google API key. Check out our [geosearch demo](https://github.com/meilisearch/demos/tree/main/src/geo-javascript) for a working example. ### Usage The classic usage, with only the `required` elements, renders an embedded Google Map on which you can move and refine search based on the position maps. ```js instantsearch.widgets.geoSearch({ container: '#maps', googleReference: window.google, }), ``` For further customization, for example to determine an initial position for the map. Contrary to `initialZoom` and `initialPosition`, triggers a search request with the provided information. The following parameters exist: - `boundingBox`: The Google Map window box. It is used as parameter in a search request. It takes precedent on all the following parameters. - `aroundLatLng`: The middle point of the Google Map. If `insideBoundingBox` or `boundingBox` is present, it is ignored. - `aroundRadius`: The radius around a Geo Point, used for sorting in the search request. It only works if `aroundLatLng` is present as well. If `insideBoundingBox` or `boundingBox` is present, it is ignored. - `insidePolygon`: Filters search results to only include documents whose coordinates fall within a specified polygon. This parameter accepts an array of coordinate pairs `[[lat, lng], [lat, lng], ...]` that define the polygon vertices (minimum 3 points required). When `insidePolygon` is specified, it takes precedence over `insideBoundingBox` and `around*` parameters. Polygon filters require documents to contain a valid `_geojson` field with [GeoJSON format](https://geojson.org/). Documents without `_geojson` will not be returned in polygon searches, even if they have `_geo` coordinates. For exemple, by adding `boundingBox` in the [`instantSearch`](#-instantsearch) widget parameters, the parameter will be used as a search parameter for the first request. ```js initialUiState: { geo: { geoSearch: { boundingBox: '50.680720183653065, 3.273798366642514,50.55969330590075, 2.9625244444490253', }, }, }, ``` Without providing this parameter, Google Maps will default to a window containing all markers from the provided search results. Alternatively, the parameters can be passed through the [`searchFunction`](https://www.algolia.com/doc/api-reference/widgets/instantsearch/js/#widget-param-searchfunction) parameter of the [`instantSearch`](#-instantsearch) widget. Contrary to `initialUiState` these parameters overwrite the values on each search. ```js searchFunction: function (helper) { helper.setQueryParameter('aroundRadius', 75000) helper.setQueryParameter('aroundLatLng', '51.1241999, 9.662499900000057'); helper.search() }, ``` You can also filter results within a polygon using `insidePolygon`. ```js search.addWidgets([ instantsearch.widgets.configure({ insidePolygon: [ [50.8466, 4.35], [50.75, 4.1], [50.65, 4.5], ], }), ]) ``` For more information, read the [geosearch documentation](https://www.meilisearch.com/docs/learn/filtering_and_sorting/geosearch). ### ❌ Answers [Answers references](https://www.algolia.com/doc/api-reference/widgets/answers/js/). No compatibility because Meilisearch does not support this experimental feature. ### βœ… RefinementList [Refinement list references](https://www.algolia.com/doc/api-reference/widgets/refinement-list/js/) The `refinementList` widget is one of the most common widgets you can find in a search UI. With this widget, the user can filter the dataset based on facets. - βœ… container: The CSS Selector or HTMLElement to insert the refinements. _required_ - βœ… attribute: The facet to display _required_ - βœ… operator: How to apply facets, `and` or `or` (`and` is the default value). - βœ… limit: How many facet values to retrieve. - βœ… showMore: Whether to display a button that expands the number of items. - βœ… showMoreLimit: The maximum number of displayed items. Does not work when showMoreLimit > limit. - βœ… searchable: Whether to add a search input to let the user search for more facet values. Not supported by Meilisearch. If you'd like to see it implemented [please vote](https://roadmap.meilisearch.com/c/64-search-for-facet-values?utm_medium=social&utm_source=portal_share). - βœ… searchablePlaceholder: The value of the search input’s placeholder. Not supported, see `searchable`. - βœ… searchableIsAlwaysActive: When false, disables the facet search input. Not supported, see `searchable`. - ❌ searchableEscapeFacetValues: When true, escapes the facet values. - ❌ sortBy: Not supported but can be implemented manually using `transformItems` options. - βœ… transformItems: A function to transform the items passed to the templates. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. The following example will create a UI component with the a list of genres on which you will be able to facet. ```js instantsearch.widgets.refinementList({ container: '#refinement-list', attribute: 'genres', }) ``` ⚠️ To make refinementList work, [please refer to this](#hierarchical-menu-usage). ### βœ… HierarchicalMenu [Hierarchical menu references](https://www.algolia.com/doc/api-reference/widgets/hierarchical-menu/js/) The `hierarchicalMenu` widget is used to create navigation based on a hierarchy of facet attributes. It is commonly used for categories with subcategories. See [usage](#hierarchical-menu-usage) below. - βœ… container: The CSS Selector or HTMLElement to insert the refinements. _required_ - βœ… attribute: The name of the attributes to generate the menu with. _required_. - βœ… limit: How many facet values to retrieve. - βœ… showMore: Whether to display a button that expands the number of items. - βœ… showMoreLimit: The maximum number of displayed items (min `2`). - ❌ separator: The level separator used in the records. (default `>`). - πŸ€·β€β™€οΈ rootPath: The prefix path to use if the first level is not the root level. - ❌ showParentLevel: Whether to show the siblings of the selected parent level of the current refined value. - βœ… sortBy: How to sort refinements. [See guide](https://www.algolia.com/doc/api-reference/widgets/hierarchical-menu/js/#widget-param-sortby) - βœ… templates: The templates to use for the widget.- βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. #### Hierarchical Menu Usage To make it work with Meilisearch your documents must have a specific structure, an explanation of the structure can [be found here](https://www.algolia.com/doc/api-reference/widgets/hierarchical-menu/js/#requirements). Contrary to `instantsearch.js`, the hierarchical fields are added in [`filterableAttributes`](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes). Example: Give the following document structure: ```json { "id": 1, "name": "Basic T-shirt", "categories.lvl0": "Men", "categories.lvl1": "Men > clothes", "categories.lvl2": "Men > clothes > t-shirt" } ``` You have to add the fields `categories.lvl0`, `categories.lvl1` and `categories.lvl2` in the `filterableAttributes` in your Meilisearch settings. ```json { "filterableAttributes": [ "categories.lvl0", "categories.lvl1", "categories.lvl2" ] } ``` ### βœ… RangeSlider [Range slider references](https://www.algolia.com/doc/api-reference/widgets/range-slider/js/) The `rangeSlider` widget provides a user-friendly way to filter the results, based on a single numeric range. - βœ… container: The CSS Selector or HTMLElement to insert the refinements. _required_ - βœ… attribute: The name of the attribute in the document. _required_. - βœ… min: The minimum value for the input. _required_ - βœ… max: The maximum value for the input. _required_ - ❌ precision: The number of digits after the decimal point to use. Not compatible as only integers work with `rangeSlider`. - βœ… step: The number of steps between each handle move. - βœ… pips: Whether to show slider pips (ruler marks). - βœ… tooltips: Whether to show tooltips. The default tooltips show the raw value. - βœ… cssClasses: The CSS classes to override. To be able to use the `rangeSlider` on an attribute, the attribute must be in the[`filterableAttributes`](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) and must contain numeric values. ### βœ… Menu [Menu references](https://www.algolia.com/doc/api-reference/widgets/menu/js/) The `menu` widget displays a menu that lets the user choose a single value for a specific attribute. - βœ… container: The CSS Selector or HTMLElement to insert the menu. _required_ - βœ… attribute: the name of the facet attribute. _required_ - βœ… limit: How many facet values to retrieve. - βœ… showMore: Whether to display a button that expands the number of items. - βœ… showMoreLimit: The maximum number of displayed items. Does not work when `showMoreLimit > limit` - ❌ sortBy: Not supported natively but can be implemented manually using `transformItems` options. - βœ… transformItems: A function to transform the items passed to the templates. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. ### βœ… currentRefinements [currentRefinements](https://www.algolia.com/doc/api-reference/widgets/current-refinements/js/) The `currentRefinements` widget displays a list of refinements applied to the search. - βœ… container: The CSS Selector or HTMLElement to insert the current refinements UI. _required_ - βœ… includedAttributes: The facet name of which checked attributes are included. - βœ… excludedAttributes: The facet name of which checked attributes are excluded. - βœ… cssClasses: The CSS classes to override. - βœ… transformItems: A function to transform the items passed to the templates. ### βœ… RangeInput [Range input references](https://www.algolia.com/doc/api-reference/widgets/range-input/js/) The `rangeInput` widget allows a user to select a numeric range using a minimum and maximum input. - βœ… container: The CSS Selector or HTMLElement to insert widget into. _required_ - βœ… attribute: The name of the attribute in the document. _required_. - βœ… min: The minimum value for the input. - βœ… max: The maximum value for the input - βœ… precision: The number of digits after the decimal point to use. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. To be able to use the `RangeInput` on an attribute, the attribute must be in the[`filterableAttributes`](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) and must contain numeric values. ### βœ… MenuSelect [Menu select references](https://www.algolia.com/doc/api-reference/widgets/menu-select/js/) The `menuSelect` widget allows a user to select a single value to refine inside a select element. - βœ… container: The CSS Selector or HTMLElement to insert widget into. _required_ - βœ… attribute: The name of the attribute in the document. _required_. - βœ… limit: How many facet values to retrieve. - ❌ [sortBy](https://www.algolia.com/doc/api-reference/widgets/menu-select/js/#widget-param-sortby): Not supported natively but can be implemented manually using `transformItems` options. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. - βœ… transformItems: A function to transform the items passed to the templates. ### βœ… ToggleRefinement [Toggle refinement references](https://www.algolia.com/doc/api-reference/widgets/toggle-refinement/js/) The numericMenu widget displays a list of numeric filters in a list. Those numeric filters are pre-configured when creating the widget. - βœ… container: The CSS Selector or HTMLElement to insert the widget into. _required_ - βœ… attribute: The name of the attribute on which apply the refinement. _required_ - βœ… on: The value of the refinement to apply on the attribute when checked. - βœ… off: The value of the refinement to apply on the attribute when unchecked. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. The toggleRefinement widget provides an on/off filtering feature based on an attribute value. ### βœ… NumericMenu [Numeric Menu references](https://www.algolia.com/doc/api-reference/widgets/numeric-menu/js/) The `numericMenu` widget displays a list of numeric filters in a list. Those numeric filters are pre-configured when creating the widget. - βœ… container: The CSS Selector or HTMLElement to insert the widget into. _required_ - βœ… attribute: The name of the attribute in the document. _required_. - βœ… items: A list of all the options to display. _required_ - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. - βœ… transformItems: function receiving the items, called before displaying them. ### βœ… RatingMenu [Rating menu references](https://www.algolia.com/doc/api-reference/widgets/rating-menu/js/) The `RatingMenu` widget lets the user refine search results by clicking on stars. The stars are based on the selected attribute. - βœ… container: The CSS Selector or HTMLElement to insert the widget into. _required_ - βœ… attribute: The name of the attribute in the document. _required_. - βœ… max: The maximum value for the rating. This value is exclusive, which means the number of stars will be the provided value, minus one. - βœ… templates: The templates to use for the widget. - βœ… cssClasses: The CSS classes to override. Contrary to `instantsearch.js`, To be able to use `RatingMenu` the field containing the rating has to be added in the [`filterableAttributes`](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) setting in your index settings. ### βœ… ClearRefinements [Clear refinements references](https://www.algolia.com/doc/api-reference/widgets/clear-refinements/js/) The `clearRefinement` widget displays a button that lets the user clean every refinement applied to the search. You can control which attributes are impacted by the button with the options. - βœ… container: The CSS Selector or HTMLElement to insert the widget into. _required_ ```js instantsearch.widgets.clearRefinements({ container: '#clear-refinements', }), ``` ### βœ… Pagination [Pagination references](https://www.algolia.com/doc/api-reference/widgets/pagination/js/) The `pagination` widget displays a pagination system allowing the user to change the current page. It should be used alongside the [`finitePagination`](#finite-pagination) setting to render the correct amount of pages. - βœ… container: The CSS Selector or HTMLElement to insert the widget in