Vite & Vue powered static site generator with Vue-based theming and markdown processing
—
VitePress theming system provides a Vue-based theme architecture with a comprehensive default theme, composables for state management, and extensive customization options. Themes can be extended, replaced, or enhanced with custom functionality.
Core theme interfaces and structure for creating custom themes.
Main theme object structure that defines how themes are implemented.
/**
* Theme object structure for VitePress themes
*/
interface Theme {
/**
* Main layout component (required for custom themes)
*/
Layout?: Component;
/**
* App enhancement function for registering components, plugins, etc.
*/
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>;
/**
* Parent theme to extend from
*/
extends?: Theme;
/**
* @deprecated Use Layout component and check useData().page.value.isNotFound
* Custom 404 Not Found component
*/
NotFound?: Component;
/**
* @deprecated Wrap your Layout component instead
* Setup function called during app initialization
*/
setup?: () => void;
}
interface EnhanceAppContext {
/**
* Vue app instance
*/
app: App;
/**
* VitePress router instance
*/
router: Router;
/**
* Reactive site data
*/
siteData: Ref<SiteData>;
}Usage Examples:
// Custom theme example
import DefaultTheme from "vitepress/theme";
import CustomLayout from "./CustomLayout.vue";
import CustomComponent from "./components/CustomComponent.vue";
const customTheme: Theme = {
extends: DefaultTheme,
Layout: CustomLayout,
enhanceApp(ctx) {
// Register custom components globally
ctx.app.component("CustomComponent", CustomComponent);
// Add custom plugins
ctx.app.use(CustomPlugin);
// Add global properties
ctx.app.config.globalProperties.$customUtility = customUtility;
// Router hooks
ctx.router.onBeforeRouteChange = (to) => {
console.log("Navigating to:", to);
};
}
};
export default customTheme;VitePress default theme with comprehensive component library and configuration options.
The main default theme object with Layout and app enhancement.
/**
* VitePress default theme
*/
declare const DefaultTheme: Theme & {
/**
* Main layout component
*/
Layout: Component;
/**
* App enhancement function
*/
enhanceApp: (ctx: EnhanceAppContext) => void;
};Usage Examples:
// Use default theme as-is
import DefaultTheme from "vitepress/theme";
export default DefaultTheme;
// Extend default theme
import DefaultTheme from "vitepress/theme";
import "./custom-styles.css";
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
// Call parent enhanceApp
DefaultTheme.enhanceApp?.(ctx);
// Add custom enhancements
ctx.app.component("MyCustomComponent", MyCustomComponent);
}
};
// Replace default theme layout
import DefaultTheme from "vitepress/theme";
import CustomLayout from "./CustomLayout.vue";
export default {
...DefaultTheme,
Layout: CustomLayout
};Comprehensive configuration interface for the default theme.
Configuration interface for customizing the default theme appearance and behavior.
/**
* Configuration interface for VitePress default theme
*/
interface DefaultTheme.Config {
/**
* Site logo configuration
*/
logo?: ThemeableImage;
/**
* Custom logo link override
*/
logoLink?: string | {
link?: string;
rel?: string;
target?: string;
};
/**
* Custom site title in navbar (overrides config.title)
*/
siteTitle?: string | false;
/**
* Navigation items in header
*/
nav?: NavItem[];
/**
* Sidebar configuration
*/
sidebar?: Sidebar;
/**
* Aside/outline configuration
*/
aside?: boolean | "left";
outline?: Outline | Outline["level"] | false;
/**
* Edit link configuration
*/
editLink?: EditLink;
/**
* Last updated configuration
*/
lastUpdated?: LastUpdatedOptions;
/**
* Document footer (prev/next) configuration
*/
docFooter?: DocFooter;
/**
* Social links in navigation
*/
socialLinks?: SocialLink[];
/**
* Footer configuration
*/
footer?: Footer;
/**
* Search configuration (local or Algolia)
*/
search?:
| { provider: "local"; options?: LocalSearchOptions }
| { provider: "algolia"; options: AlgoliaSearchOptions };
/**
* Carbon ads configuration
*/
carbonAds?: CarbonAdsOptions;
/**
* Internationalization routing
*/
i18nRouting?: boolean;
/**
* External link icon display
*/
externalLinkIcon?: boolean;
/**
* 404 page customization
*/
notFound?: NotFoundOptions;
/**
* UI text labels (for internationalization)
*/
darkModeSwitchLabel?: string;
lightModeSwitchTitle?: string;
darkModeSwitchTitle?: string;
sidebarMenuLabel?: string;
returnToTopLabel?: string;
langMenuLabel?: string;
skipToContentLabel?: string;
}
type ThemeableImage =
| string
| { src: string; alt?: string; [prop: string]: any }
| { light: string; dark: string; alt?: string; [prop: string]: any };Usage Examples:
// Complete default theme configuration
import { defineConfig } from "vitepress";
export default defineConfig({
title: "My Documentation",
themeConfig: {
logo: "/logo.svg",
siteTitle: "My Docs",
nav: [
{ text: "Guide", link: "/guide/" },
{ text: "API", link: "/api/" },
{
text: "Resources",
items: [
{ text: "Examples", link: "/examples/" },
{ text: "FAQ", link: "/faq/" }
]
}
],
sidebar: {
"/guide/": [
{
text: "Getting Started",
collapsed: false,
items: [
{ text: "Introduction", link: "/guide/" },
{ text: "Installation", link: "/guide/installation" }
]
}
]
},
editLink: {
pattern: "https://github.com/user/repo/edit/main/docs/:path",
text: "Edit this page"
},
socialLinks: [
{ icon: "github", link: "https://github.com/user/repo" },
{ icon: "twitter", link: "https://twitter.com/user" }
],
search: {
provider: "local",
options: {
translations: {
button: { buttonText: "Search" },
modal: { noResultsText: "No results found" }
}
}
}
}
});Vue composables for accessing and managing theme state within components.
Composable for managing sidebar state and behavior.
/**
* Access sidebar state and controls
* @returns DocSidebar object with sidebar state and methods
*/
function useSidebar(): DefaultTheme.DocSidebar;
interface DefaultTheme.DocSidebar {
/**
* Whether sidebar is open (mobile)
*/
isOpen: Ref<boolean>;
/**
* Computed sidebar items for current route
*/
sidebar: ComputedRef<SidebarItem[]>;
/**
* Sidebar groups (same as sidebar but different name for compatibility)
*/
sidebarGroups: ComputedRef<SidebarItem[]>;
/**
* Whether current page has sidebar
*/
hasSidebar: ComputedRef<boolean>;
/**
* Whether current page has aside/outline
*/
hasAside: ComputedRef<boolean>;
/**
* Whether aside is positioned on the left
*/
leftAside: ComputedRef<boolean>;
/**
* Whether sidebar is enabled for current route
*/
isSidebarEnabled: ComputedRef<boolean>;
/**
* Open sidebar (mobile)
*/
open(): void;
/**
* Close sidebar (mobile)
*/
close(): void;
/**
* Toggle sidebar (mobile)
*/
toggle(): void;
}Usage Examples:
<script setup>
import { useSidebar } from "vitepress/theme";
const {
isOpen,
sidebar,
hasSidebar,
hasAside,
open,
close,
toggle
} = useSidebar();
// Custom sidebar component
const handleItemClick = () => {
// Close mobile sidebar after navigation
if (window.innerWidth < 768) {
close();
}
};
</script>
<template>
<aside v-if="hasSidebar" class="custom-sidebar" :class="{ open: isOpen }">
<button @click="toggle" class="sidebar-toggle">
{{ isOpen ? 'Close' : 'Open' }} Menu
</button>
<nav class="sidebar-nav">
<div v-for="item in sidebar" :key="item.text" class="sidebar-group">
<h3 v-if="item.text">{{ item.text }}</h3>
<ul v-if="item.items">
<li v-for="child in item.items" :key="child.link">
<a :href="child.link" @click="handleItemClick">
{{ child.text }}
</a>
</li>
</ul>
</div>
</nav>
</aside>
</template>Composable for managing local navigation (table of contents) state.
/**
* Access local navigation (outline) state
* @returns DocLocalNav object with headers and visibility state
*/
function useLocalNav(): DefaultTheme.DocLocalNav;
interface DefaultTheme.DocLocalNav {
/**
* Page outline headers
*/
headers: ShallowRef<Header[]>;
/**
* Whether local nav should be shown
*/
hasLocalNav: ComputedRef<boolean>;
}Usage Examples:
<script setup>
import { useLocalNav, useData } from "vitepress/theme";
const { headers, hasLocalNav } = useLocalNav();
const { page } = useData();
// Custom table of contents component
const activeHeader = ref("");
// Track active header on scroll
onMounted(() => {
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
activeHeader.value = entry.target.id;
}
}
});
// Observe all headers
headers.value.forEach(header => {
const element = document.getElementById(header.slug);
if (element) observer.observe(element);
});
});
</script>
<template>
<nav v-if="hasLocalNav" class="local-nav">
<h4>On This Page</h4>
<ul>
<li
v-for="header in headers"
:key="header.slug"
:class="{
active: activeHeader === header.slug,
[`level-${header.level}`]: true
}"
>
<a :href="`#${header.slug}`">{{ header.title }}</a>
<!-- Nested headers -->
<ul v-if="header.children?.length">
<li
v-for="child in header.children"
:key="child.slug"
:class="{ active: activeHeader === child.slug }"
>
<a :href="`#${child.slug}`">{{ child.title }}</a>
</li>
</ul>
</li>
</ul>
</nav>
</template>Comprehensive set of Vue components provided by the default theme.
Main layout and page structure components.
/**
* Home page content area component
*/
declare const VPHomeContent: Component;
/**
* Home page features section component
*/
declare const VPHomeFeatures: Component<{
features: Feature[];
}>;
/**
* Home page hero section component
*/
declare const VPHomeHero: Component<{
name?: string;
text?: string;
tagline?: string;
image?: ThemeableImage;
actions?: HeroAction[];
}>;
/**
* Home page sponsors section component
*/
declare const VPHomeSponsors: Component<{
message?: string;
sponsors: Sponsor[];
}>;
/**
* Team page wrapper component
*/
declare const VPTeamPage: Component;
/**
* Team page section component
*/
declare const VPTeamPageSection: Component<{
title?: string;
lead?: string;
members: TeamMember[];
}>;
/**
* Team page title component
*/
declare const VPTeamPageTitle: Component<{
title: string;
lead?: string;
}>;
/**
* Team members grid component
*/
declare const VPTeamMembers: Component<{
size?: "small" | "medium";
members: TeamMember[];
}>;Reusable UI components for custom layouts and content.
/**
* Badge/tag component for highlighting information
*/
declare const VPBadge: Component<{
type?: "info" | "tip" | "warning" | "danger";
text: string;
}>;
/**
* Button component with theme styling
*/
declare const VPButton: Component<{
tag?: string | Component;
size?: "medium" | "big";
theme?: "brand" | "alt" | "sponsor";
text: string;
href?: string;
}>;
/**
* Features showcase component
*/
declare const VPFeatures: Component<{
features: Feature[];
}>;
/**
* Responsive image component with theme support
*/
declare const VPImage: Component<{
image: ThemeableImage;
alt?: string;
}>;
/**
* Enhanced link component with external link detection
*/
declare const VPLink: Component<{
tag?: string | Component;
href?: string;
noIcon?: boolean;
target?: string;
rel?: string;
}>;
/**
* Sponsors display component
*/
declare const VPSponsors: Component<{
mode: "normal" | "aside";
tier: string;
size?: "big" | "medium" | "small" | "xmini";
data: Sponsor[];
}>;Components for navigation menus and search functionality.
/**
* Navigation bar search component
*/
declare const VPNavBarSearch: Component;
/**
* Social media link component
*/
declare const VPSocialLink: Component<{
icon: SocialLinkIcon;
link: string;
ariaLabel?: string;
}>;
/**
* Social media links group component
*/
declare const VPSocialLinks: Component<{
links: SocialLink[];
}>;Components specific to documentation layouts.
/**
* Aside sponsors section component
*/
declare const VPDocAsideSponsors: Component<{
tier: string;
size?: "big" | "medium" | "small";
data: Sponsor[];
}>;Usage Examples:
<script setup>
import {
VPHomeHero,
VPHomeFeatures,
VPTeamMembers,
VPButton,
VPBadge
} from "vitepress/theme";
// Hero configuration
const heroConfig = {
name: "My Project",
text: "Next Generation Tool",
tagline: "Fast, reliable, and easy to use",
image: {
src: "/hero-logo.svg",
alt: "My Project Logo"
},
actions: [
{
theme: "brand",
text: "Get Started",
link: "/guide/getting-started"
},
{
theme: "alt",
text: "View on GitHub",
link: "https://github.com/user/project"
}
]
};
// Features configuration
const features = [
{
icon: "⚡",
title: "Fast Performance",
details: "Optimized for speed and efficiency"
},
{
icon: "🔧",
title: "Easy Configuration",
details: "Simple setup with sensible defaults"
}
];
// Team members
const teamMembers = [
{
avatar: "/avatars/john.jpg",
name: "John Doe",
title: "Lead Developer",
links: [
{ icon: "github", link: "https://github.com/johndoe" }
]
}
];
</script>
<template>
<div class="custom-layout">
<!-- Hero section -->
<VPHomeHero v-bind="heroConfig" />
<!-- Features section -->
<VPHomeFeatures :features="features" />
<!-- Team section -->
<section class="team-section">
<h2>Meet the Team</h2>
<VPTeamMembers size="medium" :members="teamMembers" />
</section>
<!-- Custom content with theme components -->
<section class="custom-content">
<h2>
Latest Release
<VPBadge type="tip" text="v2.0" />
</h2>
<p>Check out our latest features and improvements.</p>
<VPButton
theme="brand"
text="Download Now"
href="/download"
/>
</section>
</div>
</template>Supporting type definitions for theme configuration and components.
type NavItem = NavItemComponent | NavItemWithLink | NavItemWithChildren;
interface NavItemComponent {
component: string;
props?: Record<string, any>;
}
interface NavItemWithLink {
text: string;
link: string;
activeMatch?: string;
rel?: string;
target?: string;
noIcon?: boolean;
}
interface NavItemWithChildren {
text?: string;
items: (NavItemComponent | NavItemChildren | NavItemWithLink)[];
activeMatch?: string;
}
interface NavItemChildren {
text?: string;
items: NavItemWithLink[];
}type Sidebar = SidebarItem[] | SidebarMulti;
interface SidebarMulti {
[path: string]: SidebarItem[] | { items: SidebarItem[]; base: string };
}
interface SidebarItem {
text?: string;
link?: string;
items?: SidebarItem[];
collapsed?: boolean;
base?: string;
docFooterText?: string;
rel?: string;
target?: string;
}interface Feature {
icon?: FeatureIcon;
title: string;
details: string;
link?: string;
linkText?: string;
rel?: string;
target?: string;
}
type FeatureIcon =
| string
| { src: string; alt?: string; width?: string; height?: string; wrap?: boolean }
| { light: string; dark: string; alt?: string; width?: string; height?: string; wrap?: boolean };
interface TeamMember {
avatar: string;
name: string;
title?: string;
org?: string;
orgLink?: string;
desc?: string;
links?: SocialLink[];
sponsor?: string;
actionText?: string;
}
interface SocialLink {
icon: SocialLinkIcon;
link: string;
ariaLabel?: string;
}
type SocialLinkIcon = string | { svg: string };Install with Tessl CLI
npx tessl i tessl/npm-vitepress