Overview
The Search module is the core of Interface X, handling search queries, results display, facets, pagination, banners, promotions, and spellcheck suggestions. It manages the complete search experience state and coordinates with the API adapter.
State
The Search module maintains the following state:
Current search query string
Array of search result items
Partial results shown before full results load
Available facets for filtering results
Currently selected filters grouped by facet ID
Related tags for query refinement
Promotional banners to display with results
Promoted results with special positioning
Total number of results matching the query
Suggested query correction if applicable
Current page number (starts at 1)
Whether to append results (infinite scroll) or replace
Flag indicating zero results state
Whether current results came from removing filters on no-results
status
'initial' | 'loading' | 'success' | 'error'
Current request status
Additional request parameters
Origin of the search request for tracking
URL redirections for specific queries
Tagging information for query tracking
Tagging information for display events
Performance statistics for the search request
Module configuration options
Configuration
Number of results per page
pageMode
'infinite_scroll' | 'pagination'
default: "'infinite_scroll'"
How to handle multiple pages of results
Getters
Computed search request object built from current state
Current query string (passes through state)
Mutations
setQuery
(state, query: string) => void
Update the search query
setResults
(state, results: Result[]) => void
Replace all results
appendResults
(state, results: Result[]) => void
Add results to the end (for pagination/infinite scroll)
setPartialResults
(state, partialResults: PartialResult[]) => void
Set partial results shown during loading
setFacets
(state, facets: Facet[]) => void
Update available facets
setSelectedFilters
(state, filters: Filter[]) => void
Update selected filters
setRelatedTags
(state, tags: RelatedTag[]) => void
Update related tags
setBanners
(state, banners: Banner[]) => void
Update promotional banners
setPromoteds
(state, promoteds: Result[]) => void
Update promoted results
setSpellcheck
(state, query: string) => void
Set spellcheck suggestion
setTotalResults
(state, total: number) => void
Update total results count
setSort
(state, sort: string) => void
Update sort criteria
setPage
(state, page: number) => void
Update current page number
setIsAppendResults
(state, append: boolean) => void
Set whether to append or replace results
setIsNoResults
(state, isNoResults: boolean) => void
Set no results flag
setStatus
(state, status: Status) => void
Update request status
updateResult
(state, result: Result) => void
Update a specific result in the results array
Reset all state to initial values
Reset state except query, facets, sort, and page
Actions
fetchSearchResponse
(context, request?: SearchRequest) => Promise<SearchResponse>
Fetch search results from the API without updating state
fetchAndSaveSearchResponse
(context, request?: SearchRequest) => Promise<SearchResponse>
Fetch search results and update module state
cancelFetchAndSaveSearchResponse
(context) => Promise<void>
Cancel any in-progress search request
increasePageAppendingResults
(context) => Promise<void>
Load next page of results and append them
Reset page and append mode when filters change
saveSearchResponse
(context, response: SearchResponse) => void
Save a search response to state without fetching
setUrlParams
(context, params: Record<string, unknown>) => void
Update search parameters from URL
saveOrigin
(context, origin: string) => void
Save the origin of the search request
Events Emitted
Emitted when user submits a search query
Emitted when user clicks a search result
UserReachedResultsListEnd
Emitted when user scrolls to the end of results
SearchResponseChanged
{ response: SearchResponse }
Emitted when search results are updated
SearchRequestChanged
{ request: SearchRequest }
Emitted when search request parameters change
Usage Examples
Basic Search
import { useStore } from 'vuex'
import { XEvent } from '@empathyco/x-components'
const store = useStore ()
// Set query
store . commit ( 'x/search/setQuery' , 'shoes' )
// Fetch results
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
// Access results
const results = store . state . x . search . results
const totalResults = store . state . x . search . totalResults
// Configure pagination mode
store . commit ( 'x/search/setConfig' , {
pageMode: 'pagination' ,
pageSize: 20
})
// Go to page 2
store . commit ( 'x/search/setPage' , 2 )
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
// Configure infinite scroll
store . commit ( 'x/search/setConfig' , {
pageMode: 'infinite_scroll' ,
pageSize: 24
})
// Load more results
await store . dispatch ( 'x/search/increasePageAppendingResults' )
Filtering
import type { Filter } from '@empathyco/x-types'
// Select a filter
const filter : Filter = {
id: 'category:electronics' ,
facetId: 'category' ,
label: 'Electronics' ,
modelName: 'SimpleFilter' ,
selected: true ,
totalResults: 42
}
store . commit ( 'x/search/setSelectedFilters' , [ filter ])
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
Sorting
// Change sort order
store . commit ( 'x/search/setSort' , 'price:asc' )
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
Spellcheck
const spellcheck = store . state . x . search . spellcheckedQuery
if ( spellcheck ) {
// Show "Did you mean: {spellcheck}?"
store . commit ( 'x/search/setQuery' , spellcheck )
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
}
Component Integration
< template >
< div class = "search-interface" >
< div v-if = " isLoading " > Loading... </ div >
< div v-else-if = " isNoResults " >
< p > No results found for "{{ query }}" </ p >
< p v-if = " spellcheck " >
Did you mean:
< button @ click = " acceptSpellcheck " > {{ spellcheck }} </ button > ?
</ p >
</ div >
< div v-else >
< div v-for = " result in results " : key = " result . id " >
< ResultCard : result = " result " @ click = " onResultClick ( result ) " />
</ div >
< button
v-if = " hasMoreResults "
@ click = " loadMore "
>
Load More
</ button >
</ div >
</ div >
</ template >
< script setup lang = "ts" >
import { computed } from 'vue'
import { useStore } from 'vuex'
import type { Result } from '@empathyco/x-types'
import ResultCard from './ResultCard.vue'
const store = useStore ()
const query = computed (() => store . state . x . search . query )
const results = computed (() => store . state . x . search . results )
const totalResults = computed (() => store . state . x . search . totalResults )
const spellcheck = computed (() => store . state . x . search . spellcheckedQuery )
const isLoading = computed (() => store . state . x . search . status === 'loading' )
const isNoResults = computed (() => store . state . x . search . isNoResults )
const hasMoreResults = computed (() => {
return results . value . length < totalResults . value
})
const loadMore = async () => {
await store . dispatch ( 'x/search/increasePageAppendingResults' )
}
const acceptSpellcheck = async () => {
store . commit ( 'x/search/setQuery' , spellcheck . value )
await store . dispatch ( 'x/search/fetchAndSaveSearchResponse' )
}
const onResultClick = ( result : Result ) => {
// Emit tracking event
store . dispatch ( 'x/tagging/track' , {
event: 'UserClickedAResult' ,
result
})
}
</ script >
Type Reference
Source: /home/daytona/workspace/source/packages/x-components/src/x-modules/search/store/module.ts:1
Resources
x-components Main component library