Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for building UIs with Nuxt UI, the official Tailwind-based component library for Nuxt.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/layouts/docs.md
1# Docs Layout23Build documentation sites with sidebar navigation, table of contents, and surround links.45## When to use67- Technical documentation sites8- Knowledge bases, help centers9- Any content-heavy site with hierarchical navigation1011> Requires `@nuxt/content` — see [conventions](../guidelines/conventions.md#content-module-integration) for setup (module order + `@source`).1213## Component tree1415```16UApp17├── UHeader18├── UMain19│ └── NuxtLayout (docs)20│ └── UPage21│ ├── #left → UPageAside → UContentNavigation22│ └── NuxtPage23│ ├── UPageHeader24│ ├── UPageBody → ContentRenderer + UContentSurround25│ └── #right → UContentToc26└── UFooter27```2829## App shell3031```vue [app.vue]32<script setup lang="ts">33import type { NavigationMenuItem } from '@nuxt/ui'3435const route = useRoute()3637const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs'))3839provide('navigation', navigation)4041const items = computed<NavigationMenuItem[]>(() => [{42label: 'Docs',43to: '/docs/getting-started',44active: route.path.startsWith('/docs')45}])46</script>4748<template>49<UApp>50<UHeader>51<template #title>52<Logo class="h-6 w-auto" />53</template>5455<UNavigationMenu :items="items" />5657<template #right>58<UContentSearchButton />59<UColorModeButton />60</template>61</UHeader>6263<UMain>64<NuxtLayout>65<NuxtPage />66</NuxtLayout>67</UMain>6869<UFooter />7071<UContentSearch :navigation="navigation" />72</UApp>73</template>74```7576## Layout7778```vue [layouts/docs.vue]79<script setup lang="ts">80import type { ContentNavigationItem } from '@nuxt/content'8182const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')83</script>8485<template>86<UPage>87<template #left>88<UPageAside>89<UContentNavigation :navigation="navigation" />90</UPageAside>91</template>9293<slot />94</UPage>95</template>96```9798## Page99100```vue [pages/docs/[...slug].vue]101<script setup lang="ts">102const route = useRoute()103104definePageMeta({ layout: 'docs' })105106const { data: page } = await useAsyncData(route.path, () => {107return queryCollection('docs').path(route.path).first()108})109110const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {111return queryCollectionItemSurroundings('docs', route.path)112})113</script>114115<template>116<UPage>117<UPageHeader :title="page.title" :description="page.description" />118119<UPageBody>120<ContentRenderer :value="page" />121122<USeparator />123124<UContentSurround :surround="surround" />125</UPageBody>126127<template #right>128<UContentToc :links="page.body.toc.links" />129</template>130</UPage>131</template>132```133134### How nesting works135136The 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.137138### Common mistakes139140- Not providing navigation via `provide`/`inject` — the layout needs it from the app shell.141- Forgetting `UContentSearch` in app.vue — search won't work without it.142- Using `UContentSearchButton` without `UContentSearch` — the button opens search, but the search component must exist.143144## Key components145146- `UPage` — multi-column grid with `#left`, `#default`, `#right` slots147- `UPageAside` — sticky sidebar wrapper (visible from `lg` breakpoint)148- `UContentNavigation` — sidebar navigation tree from Nuxt Content149- `UContentToc` — table of contents from page headings150- `UContentSurround` — prev/next links151- `UContentSearch` / `UContentSearchButton` — search command palette152- `UPageAnchors` — simpler alternative to full TOC153