Docus is built on Nuxt, which means you can leverage Nuxt’s powerful extensibility features to customize every aspect of your documentation site.
Overriding Components
Replace any built-in Docus component by creating a file with the same name in your components/ directory.
Component Structure
Docus includes several key components you can override:
components/
├── app/
│ ├── AppHeader.vue
│ ├── AppHeaderLogo.vue
│ ├── AppHeaderBody.vue
│ ├── AppHeaderCenter.vue
│ ├── AppHeaderCTA.vue
│ ├── AppFooter.vue
│ ├── AppFooterLeft.vue
│ └── AppFooterRight.vue
Create a custom header by overriding AppHeader.vue:
[components/app/AppHeader.vue]
<template>
<UHeader>
<template #logo>
<AppHeaderLogo />
</template>
<template #center>
<AppHeaderCenter />
</template>
<template #right>
<UButton to="/docs" color="primary">
Get Started
</UButton>
<AppHeaderCTA />
</template>
</UHeader>
</template>
Create Component
Create a new component in components/app/AppHeader.vue
Copy Base Structure
Copy the base structure from the original component or create your own
Customize
Add your custom functionality, styling, or layout
Auto-Import
Nuxt automatically imports your component, overriding the default
Custom Layouts
Create custom layouts for different page types:
<template>
<div>
<AppHeader />
<main>
<slot />
</main>
<AppFooter />
</div>
</template>
Use the layout in a page:
[content/docs/special-page.md]
---
title: Special Page
layout: custom
---
This page uses a custom layout.
Layouts give you full control over page structure while reusing components like AppHeader and AppFooter.
Custom Pages
Add custom pages by creating Vue components in the pages/ directory:
<script setup lang="ts">
const { data: releases } = await useFetch('/api/releases')
</script>
<template>
<UContainer>
<PageHero title="Changelog" description="Latest updates and releases" />
<div v-for="release in releases" :key="release.id">
<h2>{{ release.name }}</h2>
<p>{{ release.body }}</p>
</div>
</UContainer>
</template>
Extending Templates
Docus provides template pages that you can extend:
Landing Page Template
The default landing page template is used when you don’t have an index.vue:
<script setup lang="ts">
const { data: page } = await useAsyncData('index', () => {
return queryCollection('landing').path('/').first()
})
if (!page.value) {
throw createError({ statusCode: 404 })
}
useSeoMeta({
title: page.value.title,
description: page.value.description,
})
</script>
<template>
<div>
<PageHero v-bind="page" />
<ContentRenderer :value="page" />
</div>
</template>
Composables
Docus provides several composables you can use in your custom components:
useDocusI18n
<script setup lang="ts">
const { isEnabled, locale, locales, t, localePath } = useDocusI18n()
</script>
<template>
<div>
<p v-if="isEnabled">Current locale: {{ locale }}</p>
<p>{{ t('docs.edit') }}</p>
</div>
</template>
useSeo
<script setup lang="ts">
useSeo({
title: 'Custom Page',
description: 'A custom page with SEO',
})
</script>
useLogoAssets
<script setup lang="ts">
const {
logo,
wordmark,
favicon,
copyLogo,
downloadLogo,
} = useLogoAssets()
</script>
<template>
<img :src="logo" alt="Logo" />
<button @click="copyLogo">Copy Logo</button>
</template>
Custom Modules
Create Nuxt modules to add functionality to Docus:
import { defineNuxtModule, addPlugin, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
meta: {
name: 'analytics',
},
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)
// Add plugin
addPlugin(resolve('./runtime/plugin'))
// Extend config
nuxt.options.runtimeConfig.public.analytics = {
enabled: true,
}
},
})
Register the module:
export default defineNuxtConfig({
modules: ['./modules/analytics'],
})
When creating custom modules, ensure they don’t conflict with Docus’s internal modules: config, routing, markdown-rewrite, and css.
Plugins
Add functionality with Nuxt plugins:
[plugins/analytics.client.ts]
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig()
if (config.public.analytics.enabled) {
// Initialize analytics
nuxtApp.hook('page:finish', () => {
// Track page view
})
}
})
Client-side
Server-side
Universal
Use .client.ts suffix for plugins that only run in the browser:// plugins/analytics.client.ts
Use .server.ts suffix for server-only plugins:// plugins/cache.server.ts
No suffix runs on both client and server:
API Routes
Add custom API endpoints:
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const results = await queryCollection('docs')
.where('title', 'contains', query.q)
.all()
return {
results,
}
})
Create Handler
Create a file in server/api/ directory
Define Logic
Implement your API logic using Nuxt Content or other data sources
Use in Frontend
Call the API from your components:const { data } = await useFetch('/api/search', {
query: { q: 'installation' },
})
Middleware
Add route middleware for authentication or redirects:
export default defineNuxtRouteMiddleware((to) => {
const user = useUser()
if (!user.value && to.path.startsWith('/admin')) {
return navigateTo('/login')
}
})
Apply globally or per-page:
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
})
</script>
Nitro Configuration
Customize the server with Nitro configuration:
export default defineNuxtConfig({
nitro: {
prerender: {
crawlLinks: true,
routes: ['/sitemap.xml'],
},
routeRules: {
'/api/**': { cors: true },
'/docs/**': { swr: 3600 },
},
},
})
nitro.prerender.crawlLinks
Automatically discover and prerender linked pages
Configure caching, headers, and redirects per route pattern
Content Hooks
Hook into content processing:
export default defineNuxtConfig({
hooks: {
'content:file:beforeParse': (file) => {
// Modify file before parsing
if (file._id.endsWith('.md')) {
// Add custom transformations
}
},
},
})
Next Steps
Nuxt Documentation
Learn more about Nuxt features
Nuxt Content
Explore Content module capabilities