Vanilla JavaScript
The Seekora UI SDK provides Vanilla JavaScript components for use without a framework.
Installation
npm install @seekora-ai/ui-sdk-vanilla @seekora-ai/search-sdk
CDN Usage
<!DOCTYPE html>
<html>
<head>
<title>Seekora Search</title>
<link rel="stylesheet" href="https://cdn.seekora.ai/ui-sdk/seekora-ui-sdk.min.css" />
</head>
<body>
<div id="search-bar"></div>
<div id="search-results"></div>
<script src="https://cdn.seekora.ai/sdk/seekora-sdk.min.js"></script>
<script src="https://cdn.seekora.ai/ui-sdk/seekora-ui-sdk-vanilla.min.js"></script>
<script>
const { SeekoraClient } = window.SeekoraSDK;
const { SearchProvider, SearchBar, SearchResults } = window.SeekoraUIVanilla;
const client = new SeekoraClient({
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});
const provider = new SearchProvider({ client });
const searchBar = new SearchBar({
container: '#search-bar',
placeholder: 'Search products...',
});
const results = new SearchResults({
container: '#search-results',
});
searchBar.mount();
results.mount();
</script>
</body>
</html>
Components
SearchProvider
The provider manages shared state and client for all components.
import { SeekoraClient } from '@seekora-ai/search-sdk';
import { SearchProvider } from '@seekora-ai/ui-sdk-vanilla';
const client = new SeekoraClient({
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});
const provider = new SearchProvider({
client,
theme: customTheme,
enableAnalytics: true,
});
// Access provider state
provider.on('stateChange', (state) => {
console.log('State:', state);
});
SearchBar
import { SearchBar } from '@seekora-ai/ui-sdk-vanilla';
const searchBar = new SearchBar({
container: '#search-bar',
placeholder: 'Search products...',
showSuggestions: true,
debounceMs: 300,
maxSuggestions: 10,
onSearch: (query, results) => {
console.log(`Found ${results.totalResults} results`);
},
onQueryChange: (query) => {
console.log('Query:', query);
},
onSuggestionSelect: (suggestion) => {
console.log('Selected:', suggestion);
},
});
// Mount to DOM
searchBar.mount();
// Programmatic control
searchBar.setQuery('laptop');
searchBar.focus();
searchBar.clear();
// Cleanup
searchBar.destroy();
SearchResults
import { SearchResults } from '@seekora-ai/ui-sdk-vanilla';
const results = new SearchResults({
container: '#search-results',
viewMode: 'grid', // 'list' | 'card' | 'grid'
itemsPerPage: 24,
// Custom rendering
renderResult: (result, index) => {
return `
<div class="product-card">
<img src="${result.image}" alt="${result.title}" />
<h3>${result.title}</h3>
<span class="price">$${result.price}</span>
</div>
`;
},
renderEmpty: () => {
return '<div class="empty">No results found</div>';
},
renderLoading: () => {
return '<div class="loading">Loading...</div>';
},
onResultClick: (result, index) => {
window.location.href = `/product/${result.id}`;
},
});
results.mount();
QuerySuggestions
import { QuerySuggestions } from '@seekora-ai/ui-sdk-vanilla';
const suggestions = new QuerySuggestions({
container: '#suggestions',
maxSuggestions: 5,
showTitle: true,
title: 'Suggestions',
renderSuggestion: (suggestion, index) => {
return `<div class="suggestion">${suggestion}</div>`;
},
onSuggestionClick: (suggestion) => {
searchBar.setQuery(suggestion);
},
});
suggestions.mount();
// Update query
suggestions.setQuery('laptop');
Facets
import { Facets } from '@seekora-ai/ui-sdk-vanilla';
const facets = new Facets({
container: '#facets',
showCount: true,
sortBy: 'count', // 'count' | 'alpha'
limit: 10,
showMore: true,
onRefinementAdd: (field, value) => {
console.log(`Added: ${field}=${value}`);
},
onRefinementRemove: (field, value) => {
console.log(`Removed: ${field}=${value}`);
},
});
facets.mount();
Pagination
import { Pagination } from '@seekora-ai/ui-sdk-vanilla';
const pagination = new Pagination({
container: '#pagination',
showFirst: true,
showLast: true,
siblingCount: 2,
onPageChange: (page) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
},
});
pagination.mount();
SortBy
import { SortBy } from '@seekora-ai/ui-sdk-vanilla';
const sortBy = new SortBy({
container: '#sort-by',
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' },
],
onChange: (value) => {
console.log('Sort:', value);
},
});
sortBy.mount();
CurrentRefinements
import { CurrentRefinements } from '@seekora-ai/ui-sdk-vanilla';
const currentRefinements = new CurrentRefinements({
container: '#current-refinements',
onRemove: (refinement) => {
console.log('Removed:', refinement);
},
});
currentRefinements.mount();
ClearRefinements
import { ClearRefinements } from '@seekora-ai/ui-sdk-vanilla';
const clearRefinements = new ClearRefinements({
container: '#clear-refinements',
label: 'Clear all filters',
onClear: () => {
console.log('Cleared all filters');
},
});
clearRefinements.mount();
Stats
import { Stats } from '@seekora-ai/ui-sdk-vanilla';
const stats = new Stats({
container: '#stats',
renderStats: (stats) => {
return `${stats.totalResults.toLocaleString()} results (${stats.processingTimeMs}ms)`;
},
});
stats.mount();
Event System
All components emit events:
const searchBar = new SearchBar({
container: '#search-bar',
});
// Listen to events
searchBar.on('search', (query, results) => {
console.log('Search:', query);
});
searchBar.on('queryChange', (query) => {
console.log('Query changed:', query);
});
searchBar.on('suggestionSelect', (suggestion) => {
console.log('Suggestion selected:', suggestion);
});
// Remove listener
searchBar.off('search', handler);
// Remove all listeners
searchBar.off('search');
State Management
Access and modify state:
const provider = new SearchProvider({ client });
// Get current state
const state = provider.getState();
console.log(state.query);
console.log(state.results);
console.log(state.refinements);
// Update state
provider.setState({
query: 'laptop',
});
// Subscribe to state changes
provider.subscribe((state) => {
console.log('State updated:', state);
});
Complete Example
<!DOCTYPE html>
<html>
<head>
<title>Seekora Search</title>
<style>
.search-page {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.search-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 24px;
margin-top: 24px;
}
.toolbar {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
}
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.product-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
}
.product-card img {
width: 100%;
height: 150px;
object-fit: cover;
}
</style>
</head>
<body>
<div class="search-page">
<header>
<div id="search-bar"></div>
</header>
<div class="search-layout">
<aside class="sidebar">
<div id="clear-refinements"></div>
<div id="facets"></div>
</aside>
<main class="content">
<div class="toolbar">
<div id="stats"></div>
<div id="current-refinements"></div>
<div id="sort-by"></div>
</div>
<div id="search-results"></div>
<div id="pagination"></div>
</main>
</div>
</div>
<script type="module">
import { SeekoraClient } from '@seekora-ai/search-sdk';
import {
SearchProvider,
SearchBar,
SearchResults,
Facets,
CurrentRefinements,
ClearRefinements,
Pagination,
SortBy,
Stats,
} from '@seekora-ai/ui-sdk-vanilla';
// Initialize client
const client = new SeekoraClient({
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});
// Create provider
const provider = new SearchProvider({
client,
enableAnalytics: true,
});
// Create components
const searchBar = new SearchBar({
container: '#search-bar',
placeholder: 'Search products...',
showSuggestions: true,
});
const searchResults = new SearchResults({
container: '#search-results',
viewMode: 'grid',
renderResult: (result) => `
<div class="product-card">
<img src="${result.image}" alt="${result.title}" />
<h3>${result.title}</h3>
<span class="price">$${result.price}</span>
</div>
`,
});
const facets = new Facets({
container: '#facets',
showCount: true,
});
const currentRefinements = new CurrentRefinements({
container: '#current-refinements',
});
const clearRefinements = new ClearRefinements({
container: '#clear-refinements',
label: 'Clear all',
});
const pagination = new Pagination({
container: '#pagination',
});
const sortBy = new SortBy({
container: '#sort-by',
items: [
{ label: 'Relevance', value: 'relevance:desc' },
{ label: 'Price: Low to High', value: 'price:asc' },
{ label: 'Price: High to Low', value: 'price:desc' },
],
});
const stats = new Stats({
container: '#stats',
});
// Mount all components
searchBar.mount();
searchResults.mount();
facets.mount();
currentRefinements.mount();
clearRefinements.mount();
pagination.mount();
sortBy.mount();
stats.mount();
// Handle page navigation
pagination.on('pageChange', (page) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
</script>
</body>
</html>
TypeScript Support
import { SeekoraClient, SearchResponse } from '@seekora-ai/search-sdk';
import {
SearchProvider,
SearchBar,
SearchResults,
SearchBarOptions,
SearchResultsOptions,
} from '@seekora-ai/ui-sdk-vanilla';
const client = new SeekoraClient({
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});
const searchBarOptions: SearchBarOptions = {
container: '#search-bar',
placeholder: 'Search...',
onSearch: (query: string, results: SearchResponse) => {
console.log(`Found ${results.totalResults} results`);
},
};
const searchBar = new SearchBar(searchBarOptions);
searchBar.mount();
Component Lifecycle
const searchBar = new SearchBar({
container: '#search-bar',
});
// Mount component
searchBar.mount();
// Check if mounted
console.log(searchBar.isMounted()); // true
// Update options
searchBar.update({
placeholder: 'New placeholder...',
});
// Temporarily hide
searchBar.hide();
// Show again
searchBar.show();
// Destroy component
searchBar.destroy();
Styling
CSS Classes
All components use BEM-style class naming:
/* SearchBar */
.seekora-search-bar { }
.seekora-search-bar__input { }
.seekora-search-bar__suggestions { }
.seekora-search-bar__suggestion { }
.seekora-search-bar__suggestion--active { }
/* SearchResults */
.seekora-search-results { }
.seekora-search-results__list { }
.seekora-search-results__item { }
.seekora-search-results__empty { }
.seekora-search-results__loading { }
/* Facets */
.seekora-facets { }
.seekora-facets__facet { }
.seekora-facets__facet-title { }
.seekora-facets__facet-values { }
.seekora-facets__facet-value { }
/* Pagination */
.seekora-pagination { }
.seekora-pagination__button { }
.seekora-pagination__button--active { }
.seekora-pagination__button--disabled { }
Custom Styling
/* Override default styles */
.seekora-search-bar__input {
border-radius: 24px;
padding: 12px 20px;
border: 2px solid #6366f1;
}
.seekora-search-bar__input:focus {
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}
.seekora-search-results__item {
transition: transform 0.2s ease;
}
.seekora-search-results__item:hover {
transform: translateY(-2px);
}
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
For older browsers, use polyfills for:
fetchPromiseCustomEventElement.closest
Next Steps
- Overview - UI SDK introduction
- React Components - React component reference
- Vue Components - Vue component reference
- Angular Components - Angular component reference