Skip to main content

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:
query
string
Current search query string
results
Result[]
Array of search result items
partialResults
PartialResult[]
Partial results shown before full results load
facets
Facet[]
Available facets for filtering results
selectedFilters
Record<string, Filter[]>
Currently selected filters grouped by facet ID
Related tags for query refinement
banners
Banner[]
Promotional banners to display with results
promoteds
Result[]
Promoted results with special positioning
totalResults
number
Total number of results matching the query
spellcheckedQuery
string
Suggested query correction if applicable
sort
string
Current sort criteria
page
number
Current page number (starts at 1)
isAppendResults
boolean
Whether to append results (infinite scroll) or replace
isNoResults
boolean
Flag indicating zero results state
fromNoResultsWithFilters
boolean
Whether current results came from removing filters on no-results
status
'initial' | 'loading' | 'success' | 'error'
Current request status
params
Record<string, unknown>
Additional request parameters
origin
string | null
Origin of the search request for tracking
redirections
Redirection[]
URL redirections for specific queries
queryTagging
TaggingInfo
Tagging information for query tracking
displayTagging
TaggingInfo
Tagging information for display events
stats
Stats
Performance statistics for the search request
config
SearchConfig
Module configuration options

Configuration

pageSize
number
default:"24"
Number of results per page
pageMode
'infinite_scroll' | 'pagination'
default:"'infinite_scroll'"
How to handle multiple pages of results

Getters

request
SearchRequest
Computed search request object built from current state
query
string
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
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
resetState
(state) => void
Reset all state to initial values
resetStateForReload
(state) => void
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
resetRequestOnRefinement
(context) => void
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

UserAcceptedAQuery
{ query: string }
Emitted when user submits a search query
UserClickedAResult
{ result: Result }
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

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

Pagination

// 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')

Infinite Scroll

// 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

x-types

Type definitions

Build docs developers (and LLMs) love