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.
<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.function useSearchCollection<T extends keyof PageCollections>(
collection: MaybeRefOrGetter<T | T[]>,
opts?: GenerateSearchSectionsOptions & { immediate?: boolean }
): {
status: Ref<'idle' | 'loading' | 'ready' | 'error'>
search: (query: string, opts?: SearchCollectionOptions) => Promise<SearchResult[]>
init: () => Promise<DatabaseAdapter>
}
collection: A single collection key, an array of collection keys, or a reactive ref/getter. When the value changes, the FTS index is rebuilt for the new collections.opts: (Optional) Index-building options:
immediate: Whether to start building the index immediately. Default is true. Set to false to defer until the first search() call or explicit init().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'.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 (typing compo matches "composable").opts: (Optional) Search options:
limit: Maximum results. Default is 20.fields: Restrict search to specific columns ('title' or 'content').minTermLength: Skip terms shorter than this value. Default is 1.weights: Control ranking behavior.
title: Boost factor for title matches. Default is 20.content: Boost factor for content matches. Default is 5.heading: Exponent controlling heading-level boost (0.5 = sqrt curve, 1 = linear, 0 = disabled). Default is 0.5.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 is 30.tag: HTML tag for highlighting. Default is 'mark'.init(): Manually trigger index building. Useful when immediate: false.interface SearchResult {
collection: string
id: string
title: string
titles: string[]
level: number
content: string
rank: number
snippets?: { title?: string, content?: string }
}
<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>
<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>
<script setup lang="ts">
const { status, search, init } = useSearchCollection('docs', {
immediate: false,
})
async function onFocus() {
if (status.value === 'idle') {
await init()
}
}
</script>
<script setup lang="ts">
const version = ref('v4')
const collection = computed(() => `nuxt-${version.value}`)
const { status, search } = useSearchCollection(collection)
</script>
<template>
<select v-model="version">
<option>v3</option>
<option>v4</option>
<option>v5</option>
</select>
</template>
When the collection value changes, the FTS index is dropped and rebuilt for the new collections.
useSearchCollection | queryCollectionSearchSections + Fuse.js | |
|---|---|---|
| Dependencies | None (built-in FTS5) | Requires external library |
| Index | SQLite inverted index | In-memory JS scan |
| Speed | O(log n) indexed 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.