--- 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