Skip to main content

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);
});
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:

  • fetch
  • Promise
  • CustomEvent
  • Element.closest

Next Steps