The <VueListSearch> component provides a search input that automatically triggers data fetching when the user types. It includes built-in debouncing to avoid excessive API calls.
Basic usage
< template >
< VueList endpoint = "users" >
< VueListSearch />
< VueListItems #default = "{ items }" >
< div v-for = "user in items" :key = "user.id" >
{{ user.name }}
</ div >
</ VueListItems >
</ VueList >
</ template >
Props
Debounce delay in milliseconds. The search won’t trigger until the user stops typing for this duration. < VueListSearch : debounce-time = " 500 " />
Slot
The default slot receives a scope object with the search state and setter:
< VueListSearch # default = " { search , setSearch } " >
<input
type="search"
:value="search"
@input="setSearch($event.target.value)"
placeholder="Search users..."
class="search-input"
/>
</ VueListSearch >
Scope object
search - Current search query string
setSearch(value) - Function to update the search (already debounced)
Behavior
Debounced by default : Waits for the user to stop typing before fetching data
Resets to page 1 : When search changes, the list automatically goes back to the first page
Accessible via requestHandler : The search value is passed to your requestHandler as context.search
Examples
< VueListSearch : debounce-time = " 300 " >
<template #default="{ search, setSearch }">
<div class="search-container">
<input
type="search"
:value="search"
@input="setSearch($event.target.value)"
placeholder="Search..."
class="px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
/>
</div>
</template>
</ VueListSearch >
With search icon
< VueListSearch >
<template #default="{ search, setSearch }">
<div class="relative">
<svg class="absolute left-3 top-3 w-5 h-5 text-gray-400" fill="none" stroke="currentColor">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
type="search"
:value="search"
@input="setSearch($event.target.value)"
placeholder="Search products..."
class="pl-10 pr-4 py-2 border rounded"
/>
</div>
</template>
</ VueListSearch >
< VueListSearch >
<template #default="{ search, setSearch }">
<div class="search-with-clear">
<input
type="search"
:value="search"
@input="setSearch($event.target.value)"
placeholder="Search..."
class="search-input"
/>
<button
v-if="search"
@click="setSearch('')"
class="clear-btn"
type="button"
>
×
</button>
</div>
</template>
</ VueListSearch >
With loading indicator
< VueList endpoint = "users" # default = " { isLoading } " >
<VueListSearch>
<template #default="{ search, setSearch }">
<div class="relative">
<input
type="search"
:value="search"
@input="setSearch($event.target.value)"
placeholder="Search users..."
class="w-full px-4 py-2 border rounded"
/>
<div v-if="isLoading" class="absolute right-3 top-3">
<svg class="animate-spin h-5 w-5 text-blue-500" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</div>
</template>
</VueListSearch>
<!-- ... items -->
</ VueList >
Advanced search with filters
< template >
< VueList endpoint = "products" v-model:filters = "filters" >
< div class = "search-bar" >
< VueListSearch :debounce-time = "500" >
< template # default = " { search , setSearch } " >
< input
type = "search"
:value = "search"
@input = "setSearch($event.target.value)"
placeholder = "Search products..."
/>
</ template >
</ VueListSearch >
< select v-model = "filters.category" >
< option value = "" > All categories </ option >
< option value = "electronics" > Electronics </ option >
< option value = "clothing" > Clothing </ option >
</ select >
< label >
< input type = "checkbox" v-model = "filters.inStock" />
In stock only
</ label >
</ div >
< VueListItems #default = "{ items }" >
<!-- render items -->
</ VueListItems >
</ VueList >
</ template >
< script setup >
import { ref } from 'vue'
const filters = ref ({
category: '' ,
inStock: false
})
</ script >
Handling search in requestHandler
The search value is passed to your request handler as context.search:
app . use ( VueList , {
requestHandler ( context ) {
const { endpoint , page , perPage , search } = context
return axios . get ( `/api/ ${ endpoint } ` , {
params: {
page ,
limit: perPage ,
q: search , // Pass search to your API
}
})
. then (({ data }) => ({
items: data . results ,
count: data . total
}))
}
})
Adjust debounceTime based on your use case:
300-500ms : Fast, responsive search for local or cached data
1000ms (default): Good balance for most APIs
1500-2000ms : Reduces load for expensive search operations
Searching automatically resets the list to page 1 to show the first page of search results.
Next steps
Filtering and sorting Combine search with filters and sorting
Request handler Learn how to handle search in your API