N
Nuxt3mo ago
Adante

Right way for full text search in Nuxt Content v3

I have Nuxt 3 app with Nuxt Content v3. What is recommended way to implement the full text search with my own Content Search component?
8 Replies
kapa.ai
kapa.ai3mo ago
Hi @Adante. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To implement full-text search in a Nuxt 3 app with Nuxt Content v3 using your own Content Search component, the recommended approach is to use the queryCollectionSearchSections utility provided by Nuxt Content. Here's how you can do it: 1. First, use the queryCollectionSearchSections utility to generate searchable sections from your content:
const { data: searchSections } = await useAsyncData('search-sections', () => {
return queryCollectionSearchSections('docs')
})
const { data: searchSections } = await useAsyncData('search-sections', () => {
return queryCollectionSearchSections('docs')
})
This will break down your content files into searchable sections. 2. Once you have the searchable sections, you can use a search library like Fuse.js or MiniSearch to implement the actual search functionality in your custom component. Here's an example using Fuse.js:
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: searchSections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

const fuse = new Fuse(searchSections.value, {
keys: ['title', 'content']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>

<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: searchSections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

const fuse = new Fuse(searchSections.value, {
keys: ['title', 'content']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>

<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
This approach allows you to create a custom search component that leverages the power of Nuxt Content's queryCollectionSearchSections utility while giving you full control over the search implementation and UI. For more detailed information and examples, you can refer to the following resources: 1. Full-Text Search documentation 2. queryCollectionSearchSections utility documentation These resources provide additional examples and explanations on implementing full-text search in Nuxt Content v3. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@384473053679190016> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Adante
AdanteOP3mo ago
@kapa.ai i want to show page icon in the searh list, how to do that?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To show a page icon in the search list, you can leverage the icon property that's typically associated with each page in Nuxt Content. Here's how you can modify your search component to include icons: 1. First, make sure your content files have an icon field in their frontmatter. For example:
---
title: My Page
icon: 'i-heroicons-document-text'
---
---
title: My Page
icon: 'i-heroicons-document-text'
---
2. When using queryCollectionSearchSections, the icon field should be included in the search results. 3. Modify your search component to display the icon. Here's an example of how you can do this:
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: searchSections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

const fuse = new Fuse(searchSections.value, {
keys: ['title', 'content', 'icon']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>

<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
<UIcon v-if="result.item.icon" :name="result.item.icon" />
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: searchSections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

const fuse = new Fuse(searchSections.value, {
keys: ['title', 'content', 'icon']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>

<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
<UIcon v-if="result.item.icon" :name="result.item.icon" />
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
In this example, we're using the UIcon component from Nuxt UI to display the icon. If the icon field is present in the search result, it will be displayed next to the title. If you're not using Nuxt UI, you can replace UIcon with your preferred icon component or a simple <i> tag with the appropriate classes. If you want to use a default icon when no specific icon is defined for a page, you can modify the template like this:
<UIcon :name="result.item.icon || 'i-heroicons-document-text'" />
<UIcon :name="result.item.icon || 'i-heroicons-document-text'" />
This will use the default icon ('i-heroicons-document-text' in this case) when no specific icon is defined for a page. For more information on customizing the search component and its appearance, you can refer to the Nuxt UI Content Search documentation. While this component is part of Nuxt UI Pro, it provides useful insights on how to structure and style your custom search component. Remember to style your icons and list items appropriately to ensure a good user experience in your search results. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@384473053679190016> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Adante
AdanteOP3mo ago
@kapa.ai but it seems that queryCollectionSearchSections does not return icon field, am i wrong?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You're correct, and I apologize for the confusion in my previous response. Let's clarify this based on the actual behavior of queryCollectionSearchSections. According to the documentation, queryCollectionSearchSections doesn't return the icon field by default. The function focuses on generating searchable sections from the content, primarily returning fields like id, title, content, and level. To include the icon in your search results, you'll need to take a different approach. Here's a more accurate way to implement this: 1. First, fetch the full content of your collection:
const { data: docs } = await useAsyncData('docs', () => queryCollection('docs').find())
const { data: docs } = await useAsyncData('docs', () => queryCollection('docs').find())
2. Then, generate the searchable sections:
const { data: sections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))
const { data: sections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))
3. Combine the two datasets in your search component:
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: docs } = await useAsyncData('docs', () => queryCollection('docs').find())
const { data: sections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

// Combine docs and sections
const searchData = computed(() => {
return sections.value.map(section => {
const doc = docs.value.find(d => d._path === section.id.split('#')[0])
return {
...section,
icon: doc?.icon
}
})
})

const fuse = new Fuse(searchData.value, {
keys: ['title', 'content', 'icon']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>
<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
<UIcon v-if="result.item.icon" :name="result.item.icon" />
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import Fuse from 'fuse.js'

const query = ref('')
const { data: docs } = await useAsyncData('docs', () => queryCollection('docs').find())
const { data: sections } = await useAsyncData('search-sections', () => queryCollectionSearchSections('docs'))

// Combine docs and sections
const searchData = computed(() => {
return sections.value.map(section => {
const doc = docs.value.find(d => d._path === section.id.split('#')[0])
return {
...section,
icon: doc?.icon
}
})
})

const fuse = new Fuse(searchData.value, {
keys: ['title', 'content', 'icon']
})

const results = computed(() => fuse.search(query.value).slice(0, 10))
</script>
<template>
<div>
<input v-model="query" placeholder="Search..." />
<ul>
<li v-for="result in results" :key="result.item.id">
<NuxtLink :to="result.item.id">
<UIcon v-if="result.item.icon" :name="result.item.icon" />
{{ result.item.title }}
</NuxtLink>
<p>{{ result.item.content.slice(0, 100) }}...</p>
</li>
</ul>
</div>
</template>
This approach combines the full document data (which includes the icon) with the searchable sections generated by queryCollectionSearchSections. For more information on querying collections and working with Nuxt Content v3, you can refer to the queryCollection documentation. I apologize again for the earlier misunderstanding. Thank you for bringing this to my attention, as it allows me to provide more accurate information. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@384473053679190016> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?