VitePress Theme Setup and Customization
VitePress provides the Default Theme with extensive customization via CSS variables and Layout slots, or complete override via Custom Theme.
CSS Variables
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand-1: #2563eb;
--vp-c-brand-2: #1d4ed8;
--vp-c-brand-3: #1e40af;
--vp-font-family-base: 'Inter', system-ui, sans-serif;
--vp-code-font-family: 'JetBrains Mono', monospace;
--vp-nav-height: 64px;
--vp-sidebar-width: 272px;
}
.dark {
--vp-c-bg: #0f172a;
--vp-c-bg-soft: #1e293b;
--vp-c-divider: #334155;
}
Extending Default Theme (Layout Slots)
// .vitepress/theme/index.ts
import { h } from 'vue';
import type { Theme } from 'vitepress';
import DefaultTheme from 'vitepress/theme';
import './custom.css';
import MyBanner from './components/MyBanner.vue';
import ApiEndpoint from './components/ApiEndpoint.vue';
export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
// Slots for content injection
'nav-bar-content-after': () => h(SearchButton),
'home-hero-info-after': () => h(MyBanner),
'doc-before': () => h(BreadcrumbNav),
'doc-footer-before': () => h(FeedbackWidget),
'aside-bottom': () => h(TableOfContentsEnhanced),
});
},
enhanceApp({ app, router, siteData }) {
// Register global components
app.component('ApiEndpoint', ApiEndpoint);
app.component('Badge', Badge);
},
} satisfies Theme;
Custom Home Layout
<!-- .vitepress/theme/components/HomeHero.vue -->
<script setup lang="ts">
import { useData } from 'vitepress';
const { frontmatter } = useData();
</script>
<template>
<section class="hero">
<div class="hero-content">
<h1>{{ frontmatter.hero.name }}</h1>
<p>{{ frontmatter.hero.tagline }}</p>
<div class="hero-actions">
<a
v-for="action in frontmatter.hero.actions"
:key="action.text"
:href="action.link"
:class="['btn', `btn--${action.theme}`]"
>
{{ action.text }}
</a>
</div>
</div>
<div class="hero-image">
<img :src="frontmatter.hero.image?.src" :alt="frontmatter.hero.image?.alt">
</div>
</section>
</template>
API Documentation Component
<!-- .vitepress/theme/components/ApiEndpoint.vue -->
<script setup lang="ts">
defineProps<{
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
path: string;
description?: string;
}>();
</script>
<template>
<div class="api-endpoint">
<div class="api-endpoint__header">
<span :class="`method method--${method.toLowerCase()}`">{{ method }}</span>
<code class="api-endpoint__path">{{ path }}</code>
</div>
<p v-if="description" class="api-endpoint__desc">{{ description }}</p>
<slot />
</div>
</template>
<style scoped>
.method { padding: 2px 8px; border-radius: 4px; font-weight: 600; font-size: 12px; }
.method--get { background: #d1fae5; color: #065f46; }
.method--post { background: #dbeafe; color: #1e40af; }
.method--delete { background: #fee2e2; color: #991b1b; }
</style>
Usage in Markdown:
<ApiEndpoint method="POST" path="/api/v1/users" description="Creates a new user">
**Request body**
| Field | Type | Required |
|---|---|---|
| name | string | Yes |
| email | string | Yes |
</ApiEndpoint>
VitePress theme customization with 3–5 components — 1–3 days.







