Query Utils
useSearchCollection
The useSearchCollection composable provides full-text search powered by SQLite FTS5, with prefix matching, BM25 ranking, and snippets.
Usage
Use the auto-imported useSearchCollection composable to search across one or more collections. It builds an FTS5 index from content sections and provides instant ranked search results.
app.vue
<script setup lang="ts">
const { status, search } = useSearchCollection('docs')
const query = ref('')
const results = ref([])
watch(query, async (value) => {
results.value = value ? await search(value) : []
})
</script>
useSearchCollection is client-only. The FTS5 index is built in the browser using SQLite WASM.Type
function useSearchCollection<T extends keyof PageCollections>(
collection: T | T[],
opts?: GenerateSearchSectionsOptions & { immediate?: boolean }
): {
status: Ref<'idle' | 'loading' | 'ready' | 'error'>
search: (query: string, opts?: SearchCollectionOptions) => Promise<SearchResult[]>
init: () => Promise<DatabaseAdapter>
}
API
Parameters
collection: A single collection key or an array of collection keys to search across.opts: (Optional) Index-building options:immediate: Whether to start building the index immediately. Default istrue. Set tofalseto defer until the firstsearch()call or explicitinit().ignoredTags: Tags to ignore when extracting section content (e.g.,['code']).minHeading: Minimum heading level to split sections on (e.g.,'h2'). Default is'h1'.maxHeading: Maximum heading level to split sections on (e.g.,'h4'). Default is'h6'.
Return Values
status: A reactive ref indicating the index state:'idle','loading','ready', or'error'.search(query, opts?): Execute a search query. Returns a promise with ranked results.query: The search string. Supports prefix matching automatically (typingcompomatches "composable").opts: (Optional) Search options:limit: Maximum results. Default is50.fields: Restrict search to specific columns ('title'or'content').minTermLength: Skip terms shorter than this value. Default is1.weights: Control ranking behavior.title: Boost factor for title matches. Default is10.content: Boost factor for content matches. Default is5.heading: Whether higher-level sections (h1 > h2 > h3) rank higher. Default istrue.
snippet: Return highlighted text excerpts.columns: Which columns to snippet (['title'],['content'], or both). Default is['content'].around: Number of tokens around the match. Default is30.tag: HTML tag for highlighting. Default is'mark'.
init(): Manually trigger index building. Useful whenimmediate: false.
Result Type
interface SearchResult {
collection: string
id: string
title: string
titles: string[]
level: number
content: string
rank: number
snippets?: { title?: string, content?: string }
}
Examples
Basic Search
SearchPage.vue
<script setup lang="ts">
const { status, search } = useSearchCollection('docs')
const query = ref('')
const results = ref([])
async function onSearch() {
results.value = query.value
? await search(query.value, { limit: 20 })
: []
}
</script>
<template>
<UInput v-model="query" :disabled="status !== 'ready'" @input="onSearch" />
<ul>
<li v-for="result in results" :key="result.id">
<NuxtLink :to="result.id">{{ result.title }}</NuxtLink>
</li>
</ul>
</template>
Multi-Collection Search
GlobalSearch.vue
<script setup lang="ts">
const { status, search } = useSearchCollection(['docs', 'blog'])
const results = ref([])
const query = ref('')
watch(query, async (value) => {
results.value = value
? await search(value, {
limit: 20,
snippet: { columns: ['content'], around: 40 },
})
: []
})
</script>
Deferred Initialization
LazySearch.vue
<script setup lang="ts">
const { status, search, init } = useSearchCollection('docs', {
immediate: false,
})
async function onFocus() {
if (status.value === 'idle') {
await init()
}
}
</script>
Compared to queryCollectionSearchSections
useSearchCollection | queryCollectionSearchSections + Fuse.js | |
|---|---|---|
| Dependencies | None (built-in FTS5) | Requires external library |
| Index | SQLite inverted index | In-memory JS scan |
| Speed | O(1) lookup | O(n) per query |
| Snippets | Built-in | Manual |
| Typo tolerance | Prefix only | Full fuzzy (edit distance) |
| Multi-collection | Native | Manual merging |
Use useSearchCollection when you need fast, zero-dependency search. Use queryCollectionSearchSections with Fuse.js or MiniSearch when you need typo-tolerant fuzzy matching.