Multiple collections (v3)
Real docs sites often have more than one collection — docs/** for guides and blog/** for posts. This recipe shows how to point <TableOfContents> at the right one.
Only applies to Content v3. On v2,
collectionis ignored — see Content v2 setup.
Define collections
// content.config.ts
import { defineContentConfig, defineCollection } from '@nuxt/content'
export default defineContentConfig({
collections: {
docs: defineCollection({ type: 'page', source: 'docs/**/*.md' }),
blog: defineCollection({ type: 'page', source: 'blog/**/*.md' }),
},
})docs: source: 'docs/**'→ reachable viaqueryCollection('docs'), path/docs/introcomes fromcontent/docs/intro.md(ordocs/intro.mddepending on yourcontentfolder placement — check what Content outputs at.path).blog: source: 'blog/**'→queryCollection('blog').
Option 1: Pass-in (recommended, most flexible)
Reuse the collection you already queried for the page:
<script setup lang="ts">
const route = useRoute()
const { data: page } = await useAsyncData(route.path, () =>
queryCollection('docs').path(route.path).first(),
)
</script>
<template>
<ContentRenderer v-if="page" :value="page" />
<!-- No collection prop — already resolved above -->
<TableOfContents :toc="page?.body?.toc" />
</template>And for a blog page:
<script setup lang="ts">
const { data: post } = await useAsyncData(route.path, () =>
queryCollection('blog').path(route.path).first(),
)
</script>
<template>
<ContentRenderer v-if="post" :value="post" />
<TableOfContents :toc="post?.body?.toc" />
</template>You never need collection on <TableOfContents> with pass-in — that’s why docs call it the “works the same on v2 and v3” mode.
Option 2: Auto-fetch by path + collection
When the TOC fetches itself:
<template>
<!-- Docs TOC -->
<TableOfContents path="/docs/intro" collection="docs" />
<!-- Blog TOC -->
<TableOfContents path="/blog/hello" collection="blog" />
</template>Resolution: props.collection || runtimeConfig.public.nuxtToc.collection || 'content' (TableOfContents.vue:230). If your nuxtToc.collection in nuxt.config.ts is "docs", the first line can omit collection="docs":
// nuxt.config.ts — global default for auto-fetch
nuxtToc: {
collection: 'docs'
}<TableOfContents path="/docs/intro" />
<!-- inherits "docs" -->
<TableOfContents path="/blog/hello" collection="blog" />
<!-- override -->Option 3: Two TOCs with different collections on one page? Use pass-in
Auto-fetch per-instance fetches exactly one document, keyed nuxt-toc-${collection}-${path}. If you need to show two outlines (e.g. docs + related posts), do two pass-in fetches:
<script setup lang="ts">
const route = useRoute()
const docsPath = '/docs/intro'
const blogPath = '/blog/hello'
const { data: docsPage } = await useAsyncData(docsPath, () =>
queryCollection('docs').path(docsPath).first(),
)
const { data: blogPage } = await useAsyncData(blogPath, () =>
queryCollection('blog').path(blogPath).first(),
)
</script>
<template>
<TableOfContents :toc="docsPage?.body?.toc" title="On this page" />
<TableOfContents :toc="blogPage?.body?.toc" title="Related post" />
</template>One TOC per page recommendation
IDs #toc-title / #toc-container are global. Two instances duplicate them. If you render two TOCs on purpose, give the second wrapper a custom CSS scope or hide the duplicate title so a11y tools do not flag duplicates.
Next: Collections for the full collection model and Auto-fetch (v3) for error states.
