Skip to main content

React Components

Complete reference for all React components in the Seekora UI SDK.

SearchProvider

The root component that provides context to all child components.

Props

PropTypeDefaultDescription
clientSeekoraClientRequiredSeekora client instance
themeThemeConfig-Custom theme configuration
enableAnalyticsbooleantrueEnable/disable analytics
autoTrackSearchbooleantrueAuto-track search events
stateManagerSearchStateManagerConfig-State manager config
childrenReactNodeRequiredChild components

Example

import { SeekoraClient } from '@seekora-ai/search-sdk';
import { SearchProvider } from '@seekora-ai/ui-sdk-react';

const client = new SeekoraClient({
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});

function App() {
return (
<SearchProvider
client={client}
enableAnalytics={true}
autoTrackSearch={true}
>
{/* Child components */}
</SearchProvider>
);
}

Interactive search input with integrated query suggestions.

Props

PropTypeDefaultDescription
placeholderstring"Search..."Input placeholder
showSuggestionsbooleantrueShow suggestions dropdown
debounceMsnumber300Debounce delay in ms
minQueryLengthnumber2Min characters for suggestions
maxSuggestionsnumber10Max suggestions to show
onSearch(query, results) => void-Search callback
onQueryChange(query) => void-Query change callback
onSuggestionSelect(suggestion) => void-Suggestion select callback
searchOptionsSearchOptions-Additional search options
classNamestring-CSS class name
styleCSSProperties-Inline styles
themeSearchBarTheme-Component theme
renderSuggestion(suggestion, index) => ReactNode-Custom suggestion render
renderLoading() => ReactNode-Custom loading render

Example

<SearchBar
placeholder="Search products..."
showSuggestions={true}
debounceMs={300}
minQueryLength={2}
maxSuggestions={8}
onSearch={(query, results) => {
console.log(`Found ${results.totalResults} results for "${query}"`);
}}
onSuggestionSelect={(suggestion) => {
console.log('Selected:', suggestion);
}}
searchOptions={{
facet_by: 'category,brand',
}}
renderSuggestion={(suggestion, index) => (
<div className="custom-suggestion">
<span>{suggestion}</span>
</div>
)}
/>

SearchResults

Displays search results with customizable rendering.

Props

PropTypeDefaultDescription
resultsSearchResponse-Search results (auto from context)
loadingboolean-Loading state
errorError-Error state
onResultClick(result, index) => void-Result click callback
renderResult(result, index, isActive) => ReactNode-Custom result render
renderEmpty() => ReactNode-Empty state render
renderLoading() => ReactNode-Loading state render
renderError(error) => ReactNode-Error state render
classNamestring-CSS class name
styleCSSProperties-Inline styles
themeSearchResultsTheme-Component theme
itemsPerPagenumber20Items per page
showPaginationbooleanfalseShow pagination
viewMode'list' | 'card' | 'grid''list'Display mode
fieldMappingFieldMapping-Field mapping
extractResults(response) => any[]-Custom result extraction
enableKeyboardNavigationbooleantrueKeyboard nav support
autoFocusbooleanfalseAuto focus first result

Example

<SearchResults
viewMode="grid"
itemsPerPage={24}
fieldMapping={{
title: 'document.name',
image: 'document.imageUrl',
price: 'document.price',
}}
onResultClick={(result, index) => {
navigate(`/product/${result.id}`);
}}
renderResult={(result, index) => (
<div className="product-card">
<img src={result.image} alt={result.title} />
<h3>{result.title}</h3>
<span className="price">${result.price}</span>
</div>
)}
renderEmpty={() => (
<div className="empty-state">
<p>No results found</p>
</div>
)}
renderLoading={() => (
<div className="skeleton-grid">
{[...Array(8)].map((_, i) => (
<div key={i} className="skeleton-card" />
))}
</div>
)}
/>

QuerySuggestions

Standalone component for displaying query suggestions.

Props

PropTypeDefaultDescription
querystring''Current query
maxSuggestionsnumber10Max suggestions
debounceMsnumber300Debounce delay
minQueryLengthnumber2Min query length
onSuggestionClick(suggestion) => void-Click callback
renderSuggestion(suggestion, index) => ReactNode-Custom render
renderLoading() => ReactNode-Loading render
renderEmpty() => ReactNode-Empty render
showTitlebooleanfalseShow title
titlestring'Suggestions'Title text
classNamestring-CSS class
styleCSSProperties-Inline styles
themeQuerySuggestionsTheme-Component theme

Example

<QuerySuggestions
query={searchQuery}
maxSuggestions={5}
showTitle={true}
title="Popular searches"
onSuggestionClick={(suggestion) => {
setSearchQuery(suggestion);
performSearch(suggestion);
}}
/>

Facets

Display and manage facet filters.

Props

PropTypeDefaultDescription
facetsRecord<string, FacetData>-Facet data (auto from context)
onRefinementAdd(field, value) => void-Add refinement callback
onRefinementRemove(field, value) => void-Remove refinement callback
showCountbooleantrueShow value counts
sortBy'count' | 'alpha''count'Sort order
limitnumber10Values per facet
showMorebooleantrueShow "show more" button
showSearchbooleanfalseShow facet search
classNamestring-CSS class

Example

<Facets
showCount={true}
sortBy="count"
limit={10}
showMore={true}
showSearch={true}
onRefinementAdd={(field, value) => {
console.log(`Added filter: ${field}=${value}`);
}}
/>

CurrentRefinements

Display active refinements/filters.

Props

PropTypeDefaultDescription
refinementsRefinement[]-Active refinements
onRemove(refinement) => void-Remove callback
renderRefinement(refinement) => ReactNode-Custom render
classNamestring-CSS class

Example

<CurrentRefinements
renderRefinement={(refinement) => (
<span className="refinement-tag">
{refinement.label}: {refinement.value}
<button onClick={() => removeRefinement(refinement)}>×</button>
</span>
)}
/>

ClearRefinements

Button to clear all active refinements.

Props

PropTypeDefaultDescription
onClear() => void-Clear callback
labelstring'Clear all'Button label
disabledboolean-Disabled state
classNamestring-CSS class

Example

<ClearRefinements
label="Clear all filters"
onClear={() => {
console.log('Filters cleared');
}}
/>

Pagination

Page navigation component.

Props

PropTypeDefaultDescription
currentPagenumber-Current page (from context)
totalPagesnumber-Total pages (from context)
onPageChange(page) => void-Page change callback
showFirstbooleantrueShow first page button
showLastbooleantrueShow last page button
showPrevNextbooleantrueShow prev/next buttons
siblingCountnumber1Pages to show around current
classNamestring-CSS class

Example

<Pagination
showFirst={true}
showLast={true}
siblingCount={2}
onPageChange={(page) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}}
/>

SortBy

Sort options dropdown.

Props

PropTypeDefaultDescription
itemsSortOption[]RequiredSort options
valuestring-Current value
onChange(value) => void-Change callback
labelstring'Sort by'Label text
classNamestring-CSS class

SortOption

interface SortOption {
label: string;
value: string;
}

Example

<SortBy
label="Sort by"
items={[
{ label: 'Relevance', value: 'relevance:desc' },
{ label: 'Price: Low to High', value: 'price:asc' },
{ label: 'Price: High to Low', value: 'price:desc' },
{ label: 'Newest First', value: 'created_at:desc' },
{ label: 'Best Selling', value: 'sales:desc' },
]}
onChange={(value) => {
console.log('Sort changed to:', value);
}}
/>

HitsPerPage

Results per page selector.

Props

PropTypeDefaultDescription
itemsnumber[][10, 20, 50]Options
valuenumber-Current value
onChange(value) => void-Change callback
labelstring'Show'Label text
classNamestring-CSS class

Example

<HitsPerPage
items={[12, 24, 48, 96]}
label="Products per page"
/>

Stats

Search statistics display.

Props

PropTypeDefaultDescription
totalResultsnumber-Total results (from context)
processingTimeMsnumber-Processing time
renderStats(stats) => ReactNode-Custom render
classNamestring-CSS class

Example

<Stats
renderStats={({ totalResults, processingTimeMs }) => (
<span>
{totalResults.toLocaleString()} results
({processingTimeMs}ms)
</span>
)}
/>

RangeSlider

Numeric range filter slider.

Props

PropTypeDefaultDescription
attributestringRequiredField name
minnumber-Minimum value
maxnumber-Maximum value
stepnumber1Step increment
onChange(range) => void-Change callback
formatValue(value) => string-Value formatter
classNamestring-CSS class

Example

<RangeSlider
attribute="price"
min={0}
max={1000}
step={10}
formatValue={(value) => `$${value}`}
onChange={({ min, max }) => {
addFilter('price', `${min}-${max}`);
}}
/>

Highlight

Highlight matching text in results.

Props

PropTypeDefaultDescription
hitobjectRequiredResult object
attributestringRequiredField to highlight
tagNamestring'mark'Highlight tag
classNamestring-CSS class

Example

<Highlight 
hit={result}
attribute="title"
tagName="mark"
/>

InfiniteHits

Infinite scroll results display.

Props

PropTypeDefaultDescription
thresholdnumber200Load threshold in px
renderResult(result, index) => ReactNode-Result render
renderLoading() => ReactNode-Loading render
renderEnd() => ReactNode-End of results render
classNamestring-CSS class

Example

<InfiniteHits
threshold={300}
renderResult={(result) => (
<ProductCard product={result} />
)}
renderLoading={() => (
<div className="loading-spinner" />
)}
renderEnd={() => (
<p>You've reached the end!</p>
)}
/>

Field Mapping

Configure how component fields map to your data:

interface FieldMapping {
title?: string; // e.g., 'document.productName'
description?: string; // e.g., 'document.brandDesc'
image?: string; // e.g., 'document.image'
price?: string; // e.g., 'document.mrp'
url?: string; // e.g., 'document.url'
id?: string; // e.g., 'id'
primaryText?: string; // Widget view field
secondaryText?: string; // Widget view field
tertiaryText?: string; // Widget view field
imageUrl?: string; // Widget view field
custom?: Record<string, string>; // Custom fields
}

Example with Nested Fields

<SearchProvider
client={client}
fieldMapping={{
title: 'document.product.name',
description: 'document.product.description',
image: 'document.images[0].url',
price: 'document.pricing.current',
id: 'id',
}}
>
<SearchResults />
</SearchProvider>

Next Steps