Setting the file. One moment.
Subchapter 1.8
references/layouts/docs.mdMarkdown4 KBView on GitHub
Build documentation sites with sidebar navigation, table of contents, and surround links.
Requires
@nuxt/content— see conventions for setup (module order +@source).
UApp
├── UHeader
├── UMain
│ └── NuxtLayout (docs)
│ └── UPage
│ ├── #left → UPageAside → UContentNavigation
│ └── NuxtPage
│ ├── UPageHeader
│ ├── UPageBody → ContentRenderer + UContentSurround
│ └── #right → UContentToc
└── UFooter<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const route = useRoute()
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs'))
provide('navigation', navigation)
const items = computed<NavigationMenuItem[]>(() => [{
label: 'Docs',
to: '/docs/getting-started',
active: route.path.startsWith('/docs')
}])
</script>
<template>
<UApp>
<UHeader>
<template #title>
<Logo class="h-6 w-auto" />
</template>
<UNavigationMenu :items="items" />
<template #right>
<UContentSearchButton />
<UColorModeButton />
</template>
</UHeader>
<UMain>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</UMain>
<UFooter />
<UContentSearch :navigation="navigation" />
</UApp>
</template><script setup lang="ts">
import type { ContentNavigationItem } from '@nuxt/content'
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>
<template>
<UPage>
<template #left>
<UPageAside>
<UContentNavigation :navigation="navigation" />
</UPageAside>
</template>
<slot />
</UPage>
</template><script setup lang="ts">
const route = useRoute()
definePageMeta({ layout: 'docs' })
const { data: page } = await useAsyncData(route.path, () => {
return queryCollection('docs').path(route.path).first()
})
const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
return queryCollectionItemSurroundings('docs', route.path)
})
</script>
<template>
<UPage>
<UPageHeader :title="page.title" :description="page.description" />
<UPageBody>
<ContentRenderer :value="page" />
<USeparator />
<UContentSurround :surround="surround" />
</UPageBody>
<template #right>
<UContentToc :links="page.body.toc.links" />
</template>
</UPage>
</template>The outer UPage in the layout handles the left sidebar. The inner UPage in the page handles the right sidebar. They nest correctly — this is intentional.
provide/inject — the layout needs it from the app shell.UContentSearch in app.vue — search won’t work without it.UContentSearchButton without UContentSearch — the button opens search, but the search component must exist.UPage — multi-column grid with #left, #default, #right slotsUPageAside — sticky sidebar wrapper (visible from lg breakpoint)UContentNavigation — sidebar navigation tree from Nuxt ContentUContentToc — table of contents from page headingsUContentSurround — prev/next linksUContentSearch / UContentSearchButton — search command paletteUPageAnchors — simpler alternative to full TOC