Skip to main content

Vue Components

The Seekora UI SDK provides Vue 3 components that mirror the React component API.

Installation

npm install @seekora-ai/ui-sdk-vue @seekora-ai/search-sdk

Setup

Basic Setup

<template>
<SearchProvider :client="client">
<SearchBar placeholder="Search products..." />
<SearchResults />
</SearchProvider>
</template>

<script setup>
import { SeekoraClient } from '@seekora-ai/search-sdk';
import { SearchProvider, SearchBar, SearchResults } from '@seekora-ai/ui-sdk-vue';

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

With Plugin

// main.ts
import { createApp } from 'vue';
import { SeekoraPlugin } from '@seekora-ai/ui-sdk-vue';
import App from './App.vue';

const app = createApp(App);

app.use(SeekoraPlugin, {
storeId: 'your-store-id',
readSecret: 'your-read-secret',
});

app.mount('#app');
<!-- App.vue -->
<template>
<SearchProvider>
<SearchBar />
<SearchResults />
</SearchProvider>
</template>

<script setup>
import { SearchProvider, SearchBar, SearchResults } from '@seekora-ai/ui-sdk-vue';
</script>

Components

SearchProvider

<template>
<SearchProvider
:client="client"
:theme="customTheme"
:enable-analytics="true"
>
<slot />
</SearchProvider>
</template>

<script setup>
import { SearchProvider } from '@seekora-ai/ui-sdk-vue';

const props = defineProps({
client: { type: Object, required: true },
theme: { type: Object, default: null },
enableAnalytics: { type: Boolean, default: true },
});
</script>
<template>
<SearchBar
placeholder="Search products..."
:show-suggestions="true"
:debounce-ms="300"
:max-suggestions="10"
@search="handleSearch"
@query-change="handleQueryChange"
@suggestion-select="handleSuggestionSelect"
/>
</template>

<script setup>
import { SearchBar } from '@seekora-ai/ui-sdk-vue';

const handleSearch = (query, results) => {
console.log(`Found ${results.totalResults} results for "${query}"`);
};

const handleQueryChange = (query) => {
console.log('Query:', query);
};

const handleSuggestionSelect = (suggestion) => {
console.log('Selected:', suggestion);
};
</script>

SearchResults

<template>
<SearchResults
view-mode="grid"
:items-per-page="24"
@result-click="handleResultClick"
>
<template #result="{ result, index }">
<div class="product-card">
<img :src="result.image" :alt="result.title" />
<h3>{{ result.title }}</h3>
<span class="price">${{ result.price }}</span>
</div>
</template>

<template #empty>
<div class="empty-state">
<p>No results found</p>
</div>
</template>

<template #loading>
<div class="loading">Loading...</div>
</template>
</SearchResults>
</template>

<script setup>
import { SearchResults } from '@seekora-ai/ui-sdk-vue';

const handleResultClick = (result, index) => {
router.push(`/product/${result.id}`);
};
</script>

QuerySuggestions

<template>
<QuerySuggestions
:query="searchQuery"
:max-suggestions="5"
:show-title="true"
title="Suggestions"
@suggestion-click="handleSuggestionClick"
>
<template #suggestion="{ suggestion, index }">
<div class="suggestion-item">
<SearchIcon />
<span>{{ suggestion }}</span>
</div>
</template>
</QuerySuggestions>
</template>

<script setup>
import { ref } from 'vue';
import { QuerySuggestions } from '@seekora-ai/ui-sdk-vue';

const searchQuery = ref('');

const handleSuggestionClick = (suggestion) => {
searchQuery.value = suggestion;
};
</script>

Facets

<template>
<Facets
:show-count="true"
sort-by="count"
:limit="10"
:show-more="true"
@refinement-add="handleRefinementAdd"
@refinement-remove="handleRefinementRemove"
/>
</template>

<script setup>
import { Facets } from '@seekora-ai/ui-sdk-vue';

const handleRefinementAdd = (field, value) => {
console.log(`Added: ${field}=${value}`);
};

const handleRefinementRemove = (field, value) => {
console.log(`Removed: ${field}=${value}`);
};
</script>

Pagination

<template>
<Pagination
:show-first="true"
:show-last="true"
:sibling-count="2"
@page-change="handlePageChange"
/>
</template>

<script setup>
import { Pagination } from '@seekora-ai/ui-sdk-vue';

const handlePageChange = (page) => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
</script>

SortBy

<template>
<SortBy
label="Sort by"
:items="sortOptions"
@change="handleSortChange"
/>
</template>

<script setup>
import { SortBy } from '@seekora-ai/ui-sdk-vue';

const sortOptions = [
{ label: 'Relevance', value: 'relevance:desc' },
{ label: 'Price: Low to High', value: 'price:asc' },
{ label: 'Price: High to Low', value: 'price:desc' },
];

const handleSortChange = (value) => {
console.log('Sort:', value);
};
</script>

Composables

useSeekoraSearch

<script setup>
import { ref } from 'vue';
import { useSeekoraSearch } from '@seekora-ai/ui-sdk-vue';

const { search, results, loading, error, clearResults } = useSeekoraSearch({
client,
autoTrack: true,
});

const query = ref('');

const handleSearch = async () => {
await search(query.value, {
per_page: 20,
facet_by: 'category,brand',
});
};
</script>

<template>
<div>
<input v-model="query" @keyup.enter="handleSearch" />
<button @click="handleSearch" :disabled="loading">
{{ loading ? 'Searching...' : 'Search' }}
</button>

<div v-if="error">{{ error.message }}</div>

<div v-if="results">
<div v-for="result in results.results" :key="result.id">
{{ result.title }}
</div>
</div>
</div>
</template>

useQuerySuggestions

<script setup>
import { ref, watch } from 'vue';
import { useQuerySuggestions } from '@seekora-ai/ui-sdk-vue';

const query = ref('');

const { suggestions, loading, error } = useQuerySuggestions({
client,
query,
debounceMs: 300,
maxSuggestions: 8,
});
</script>

<template>
<div>
<input v-model="query" />

<ul v-if="suggestions.length > 0">
<li v-for="(suggestion, index) in suggestions" :key="index">
{{ suggestion }}
</li>
</ul>
</div>
</template>

useSearchState

<script setup>
import { useSearchState } from '@seekora-ai/ui-sdk-vue';

const {
query,
setQuery,
results,
currentPage,
setPage,
refinements,
addRefinement,
removeRefinement,
clearRefinements,
sortBy,
setSortBy,
} = useSearchState();
</script>

<template>
<div>
<input :value="query" @input="setQuery($event.target.value)" />

<div v-for="ref in refinements" :key="`${ref.field}-${ref.value}`">
{{ ref.field }}: {{ ref.value }}
<button @click="removeRefinement(ref.field, ref.value)">×</button>
</div>

<button v-if="refinements.length" @click="clearRefinements">
Clear all
</button>

<div v-if="results">
Found {{ results.totalResults }} results
</div>
</div>
</template>

useSearchContext

<script setup>
import { useSearchContext } from '@seekora-ai/ui-sdk-vue';

const { client, theme, analytics } = useSearchContext();
</script>

Complete Example

<template>
<SearchProvider :client="client" :theme="theme">
<div class="search-page">
<header>
<SearchBar
placeholder="Search products..."
:show-suggestions="true"
@search="handleSearch"
/>
</header>

<div class="search-layout">
<aside class="sidebar">
<ClearRefinements />
<Facets :show-count="true" />
</aside>

<main class="content">
<div class="toolbar">
<Stats />
<CurrentRefinements />
<SortBy :items="sortOptions" />
</div>

<SearchResults view-mode="grid">
<template #result="{ result }">
<ProductCard :product="result" />
</template>
</SearchResults>

<Pagination />
</main>
</div>
</div>
</SearchProvider>
</template>

<script setup>
import { SeekoraClient } from '@seekora-ai/search-sdk';
import {
SearchProvider,
SearchBar,
SearchResults,
Facets,
CurrentRefinements,
ClearRefinements,
Pagination,
SortBy,
Stats,
} from '@seekora-ai/ui-sdk-vue';
import ProductCard from './ProductCard.vue';

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

const theme = {
colors: {
primary: '#6366f1',
},
};

const sortOptions = [
{ label: 'Relevance', value: 'relevance:desc' },
{ label: 'Price: Low to High', value: 'price:asc' },
{ label: 'Price: High to Low', value: 'price:desc' },
];

const handleSearch = (query, results) => {
console.log(`Found ${results.totalResults} results`);
};
</script>

<style scoped>
.search-page {
max-width: 1200px;
margin: 0 auto;
}

.search-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 24px;
margin-top: 24px;
}

.toolbar {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
}
</style>

TypeScript Support

<script setup lang="ts">
import { ref } from 'vue';
import { SeekoraClient, SearchResponse } from '@seekora-ai/search-sdk';
import { SearchProvider, SearchBar, SearchResults } from '@seekora-ai/ui-sdk-vue';
import type { SearchBarProps, Theme } from '@seekora-ai/ui-sdk-vue';

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

const theme: Partial<Theme> = {
colors: {
primary: '#6366f1',
},
};

const handleSearch = (query: string, results: SearchResponse) => {
console.log(`Found ${results.totalResults} results`);
};
</script>

Next Steps