--- name: vitepress-custom-themes description: Building custom themes from scratch with the theme interface, Layout component, and enhanceApp --- # Custom Themes Build a theme from scratch when the default theme doesn't fit your needs. ## Theme Entry Create `.vitepress/theme/index.ts`: ```ts // .vitepress/theme/index.ts import Layout from './Layout.vue'; export default { Layout, enhanceApp({ app, router, siteData }) { // Register global components, plugins, etc. }, }; ``` ## Theme Interface ```ts interface Theme { // Required: Root layout component Layout: Component; // Optional: Enhance Vue app instance enhanceApp?: (ctx: EnhanceAppContext) => Awaitable; // Optional: Extend another theme extends?: Theme; } interface EnhanceAppContext { app: App; // Vue app instance router: Router; // VitePress router siteData: Ref; // Site-level metadata } ``` ## Basic Layout The Layout component must render `` for markdown: ```vue ``` ## Runtime API Access VitePress data in your theme: ```vue ``` ## Built-in Components ```vue ``` ## Extend Another Theme Build on top of default theme or any other: ```ts // .vitepress/theme/index.ts import DefaultTheme from 'vitepress/theme'; export default { extends: DefaultTheme, enhanceApp({ app }) { // Your customizations }, }; ``` ## Register Plugins and Components ```ts // .vitepress/theme/index.ts import Layout from './Layout.vue'; import GlobalComponent from './GlobalComponent.vue'; export default { Layout, enhanceApp({ app }) { // Register global component app.component('GlobalComponent', GlobalComponent); // Register plugin app.use(MyPlugin); // Provide/inject app.provide('key', value); }, }; ``` ## Async enhanceApp For plugins that need async initialization: ```ts export default { Layout, async enhanceApp({ app }) { if (!import.meta.env.SSR) { // Client-only plugin const plugin = await import('browser-only-plugin'); app.use(plugin.default); } }, }; ``` ## Theme-Aware Layout Handle different page layouts: ```vue ``` ## Distributing a Theme As npm package: ```ts // my-theme/index.ts import Layout from './Layout.vue'; export default { Layout }; // Export types for config export type { ThemeConfig } from './types'; ``` Consumer usage: ```ts // .vitepress/theme/index.ts import Theme from 'my-vitepress-theme'; export default Theme; // Or extend it export default { extends: Theme, enhanceApp({ app }) { // Additional customization }, }; ``` ## Theme Config Types For custom theme config types: ```ts // .vitepress/config.ts import { defineConfigWithTheme } from 'vitepress'; import type { ThemeConfig } from 'my-theme'; export default defineConfigWithTheme({ themeConfig: { // Type-checked theme config }, }); ``` ## Key Points - Theme must export `Layout` component - `` renders the markdown content - Use `useData()` to access page/site data - `enhanceApp` runs on both server and client - Check `import.meta.env.SSR` for client-only code - Use `extends` to build on existing themes