This example demonstrates a full-featured e-commerce search experience with product listings, multiple filters, sorting options, and responsive design.
Overview
The e-commerce example includes:
Product search with highlighting and snippeting
Faceted navigation (categories, brands, ratings, price)
Sorting by relevance, price ascending/descending
Pagination for browsing results
URL routing to sync search state with the browser URL
Responsive design with mobile-optimized filters
Live Demo
Try the Live Demo Experience the e-commerce search example in action
Implementation
JavaScript Example
Basic Setup
Add Widgets
Product Template
Initialize InstantSearch with the search client and routing: import { liteClient as algoliasearch } from 'algoliasearch/lite' ;
import instantsearch from 'instantsearch.js' ;
import getRouting from './routing' ;
const searchClient = algoliasearch (
'latency' ,
'6be0576ff61c053d5f9a3225e2a90f76'
);
const search = instantsearch ({
searchClient ,
indexName: 'instant_search' ,
routing: getRouting ({ indexName: 'instant_search' }),
insights: true ,
});
Add search widgets for the complete experience: import {
searchBox ,
hits ,
refinementList ,
hierarchicalMenu ,
rangeSlider ,
pagination ,
sortBy ,
hitsPerPage ,
} from 'instantsearch.js/es/widgets' ;
search . addWidgets ([
searchBox ({
container: '#search-box' ,
placeholder: 'Search for products...' ,
}),
hierarchicalMenu ({
container: '#categories' ,
attributes: [
'hierarchicalCategories.lvl0' ,
'hierarchicalCategories.lvl1' ,
],
}),
refinementList ({
container: '#brands' ,
attribute: 'brand' ,
searchable: true ,
searchablePlaceholder: 'Search for brands…' ,
}),
rangeSlider ({
container: '#price-range' ,
attribute: 'price' ,
tooltips: {
format ( value ) {
return `$ ${ Math . round ( value ) } ` ;
},
},
}),
sortBy ({
container: '#sort-by' ,
items: [
{ label: 'Featured' , value: 'instant_search' },
{ label: 'Price (asc)' , value: 'instant_search_price_asc' },
{ label: 'Price (desc)' , value: 'instant_search_price_desc' },
],
}),
hits ({
container: '#products' ,
templates: {
item ( hit , { html , components }) {
return html `
<article class="hit">
<img src=" ${ hit . image } " alt=" ${ hit . name } " />
<div>
<h3> ${ components . Highlight ({ hit , attribute: 'name' }) } </h3>
<p class="price">$ ${ hit . price } </p>
<div class="rating">⭐ ${ hit . rating } </div>
</div>
</article>
` ;
},
},
}),
pagination ({
container: '#pagination' ,
}),
]);
search . start ();
Customize the product display with a detailed template: import { hits } from 'instantsearch.js/es/widgets' ;
const products = hits ({
container: '[data-widget="hits"]' ,
templates: {
item ( hit , { html , components }) {
return html `
<article class="hit">
<header class="hit-image-container">
<img src=" ${ hit . image } " alt=" ${ hit . name } " class="hit-image" />
</header>
<div class="hit-info-container">
<p class="hit-category"> ${ hit . categories [ 0 ] } </p>
<h1> ${ components . Highlight ({ hit , attribute: 'name' }) } </h1>
<p class="hit-description">
${ components . Snippet ({ attribute: 'description' , hit }) }
</p>
<footer>
<p>
<span class="hit-em">$</span>
<strong> ${ hit . price . toLocaleString () } </strong>
<span class="hit-em hit-rating">
⭐ ${ hit . rating }
</span>
</p>
</footer>
</div>
</article>
` ;
},
},
});
React Example
The React implementation uses InstantSearch components:
import { liteClient as algoliasearch } from 'algoliasearch/lite' ;
import {
Configure ,
HierarchicalMenu ,
Hits ,
HitsPerPage ,
InstantSearch ,
Pagination ,
RefinementList ,
SearchBox ,
SortBy ,
ToggleRefinement ,
Highlight ,
Snippet ,
} from 'react-instantsearch' ;
const searchClient = algoliasearch (
'latency' ,
'6be0576ff61c053d5f9a3225e2a90f76'
);
function Hit ({ hit }) {
return (
< article className = "hit" >
< img src = { hit . image } alt = { hit . name } />
< div >
< h3 >
< Highlight attribute = "name" hit = { hit } />
</ h3 >
< p className = "description" >
< Snippet attribute = "description" hit = { hit } />
</ p >
< div className = "price" > $ { hit . price } </ div >
</ div >
</ article >
);
}
export function App () {
return (
< InstantSearch
searchClient = { searchClient }
indexName = "instant_search"
insights = { true }
>
< Configure hitsPerPage = { 16 } />
< div className = "search-panel" >
< div className = "filters" >
< HierarchicalMenu
attributes = { [
'hierarchicalCategories.lvl0' ,
'hierarchicalCategories.lvl1' ,
] }
/>
< RefinementList
attribute = "brand"
searchable = { true }
searchablePlaceholder = "Search brands…"
/>
< ToggleRefinement
attribute = "free_shipping"
label = "Free shipping"
/>
</ div >
< div className = "results" >
< SearchBox placeholder = "Search products…" />
< div className = "options" >
< SortBy
items = { [
{ label: 'Featured' , value: 'instant_search' },
{ label: 'Price (asc)' , value: 'instant_search_price_asc' },
{ label: 'Price (desc)' , value: 'instant_search_price_desc' },
] }
/>
< HitsPerPage
items = { [
{ label: '16 per page' , value: 16 , default: true },
{ label: '32 per page' , value: 32 },
{ label: '64 per page' , value: 64 },
] }
/>
</ div >
< Hits hitComponent = { Hit } />
< Pagination />
</ div >
</ div >
</ InstantSearch >
);
}
Key Features
Hierarchical Categories
Navigate through nested product categories:
hierarchicalMenu ({
container: '#categories' ,
attributes: [
'hierarchicalCategories.lvl0' ,
'hierarchicalCategories.lvl1' ,
'hierarchicalCategories.lvl2' ,
],
})
Price Range Slider
Filter products by price with a visual slider:
rangeSlider ({
container: '#price' ,
attribute: 'price' ,
pips: false ,
tooltips: {
format ( value ) {
return `$ ${ Math . round ( value ). toLocaleString () } ` ;
},
},
})
Searchable Facets
Allow users to search within large facet lists:
refinementList ({
container: '#brands' ,
attribute: 'brand' ,
searchable: true ,
searchablePlaceholder: 'Search for brands…' ,
showMore: true ,
showMoreLimit: 50 ,
})
Rating Filter
Filter by minimum rating:
ratingMenu ({
container: '#ratings' ,
attribute: 'rating' ,
max: 5 ,
})
Responsive Design
The example includes mobile-optimized filtering:
// Mobile filter toggle
const openFiltersButton = document . querySelector ( '[data-action="open-overlay"]' );
const closeFiltersButton = document . querySelector ( '[data-action="close-overlay"]' );
openFiltersButton . addEventListener ( 'click' , () => {
document . body . classList . add ( 'filtering' );
});
closeFiltersButton . addEventListener ( 'click' , () => {
document . body . classList . remove ( 'filtering' );
});
Index Configuration
The example uses multiple replica indices for sorting:
instant_search - Default relevance ranking
instant_search_price_asc - Price ascending
instant_search_price_desc - Price descending
Configure replica indices in your Algolia dashboard under Index > Replicas
Running the Example
cd examples/js/e-commerce
yarn install
yarn start
cd examples/react/e-commerce
yarn install
yarn start
cd examples/vue/e-commerce
yarn install
yarn dev
Customization Tips
Change the product data structure
Modify the hit template to match your product schema. Update attribute names in widgets to match your index configuration.
Include additional refinementList widgets for attributes like color, size, or material.
The example uses custom CSS built on top of InstantSearch CSS themes. Modify the styles to match your brand.
Add to cart functionality
Integrate with your e-commerce platform by adding click handlers to product items.
Source Code