mirror of https://github.com/vuejs/vitepress
parent
b9aed5695a
commit
6c4dea4b63
@ -1,228 +1 @@
|
|||||||
# Theme Introduction
|
# Building a Custom Theme
|
||||||
|
|
||||||
VitePress comes with its default theme providing many features out of the box. Learn more about each feature on its dedicated page listed below.
|
|
||||||
|
|
||||||
- [Nav](/reference/default-theme-nav)
|
|
||||||
- [Sidebar](/reference/default-theme-sidebar)
|
|
||||||
- [Prev Next Link](/reference/default-theme-prev-next-link)
|
|
||||||
- [Edit Link](/reference/default-theme-edit-link)
|
|
||||||
- [Last Updated](/reference/default-theme-last-updated)
|
|
||||||
- [Layout](/reference/default-theme-layout)
|
|
||||||
- [Home Page](/reference/default-theme-home-page)
|
|
||||||
- [Team Page](/reference/default-theme-team-page)
|
|
||||||
- [Badge](/reference/default-theme-badge)
|
|
||||||
- [Footer](/reference/default-theme-footer)
|
|
||||||
- [Search](/reference/default-theme-search)
|
|
||||||
- [Carbon Ads](/reference/default-theme-carbon-ads)
|
|
||||||
|
|
||||||
If you don't find the features you're looking for, or you would rather create your own theme, you may customize VitePress to fit your requirements. In the following sections, we'll go through each way of customizing the VitePress theme.
|
|
||||||
|
|
||||||
## Using a Custom Theme
|
|
||||||
|
|
||||||
You can enable a custom theme by adding the `.vitepress/theme/index.js` or `.vitepress/theme/index.ts` file (the "theme entry file").
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├─ docs
|
|
||||||
│ ├─ .vitepress
|
|
||||||
│ │ ├─ theme
|
|
||||||
│ │ │ └─ index.js
|
|
||||||
│ │ └─ config.js
|
|
||||||
│ └─ index.md
|
|
||||||
└─ package.json
|
|
||||||
```
|
|
||||||
|
|
||||||
A VitePress custom theme is simply an object containing four properties and is defined as follows:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface Theme {
|
|
||||||
Layout: Component // Vue 3 component
|
|
||||||
NotFound?: Component
|
|
||||||
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
|
|
||||||
setup?: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EnhanceAppContext {
|
|
||||||
app: App // Vue 3 app instance
|
|
||||||
router: Router // VitePress router instance
|
|
||||||
siteData: Ref<SiteData>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The theme entry file should export the theme as its default export:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import Layout from './Layout.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
// root component to wrap each page
|
|
||||||
Layout,
|
|
||||||
|
|
||||||
// this is a Vue 3 functional component
|
|
||||||
NotFound: () => 'custom 404',
|
|
||||||
|
|
||||||
enhanceApp({ app, router, siteData }) {
|
|
||||||
// app is the Vue 3 app instance from `createApp()`.
|
|
||||||
// router is VitePress' custom router. `siteData` is
|
|
||||||
// a `ref` of current site-level metadata.
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
// this function will be executed inside VitePressApp's
|
|
||||||
// setup hook. all composition APIs are available here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
...where the `Layout` component could look like this:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<!-- .vitepress/theme/Layout.vue -->
|
|
||||||
<template>
|
|
||||||
<h1>Custom Layout!</h1>
|
|
||||||
|
|
||||||
<!-- this is where markdown content will be rendered -->
|
|
||||||
<Content />
|
|
||||||
</template>
|
|
||||||
```
|
|
||||||
|
|
||||||
The default export is the only contract for a custom theme. Inside your custom theme, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./using-vue#browser-api-access-restrictions).
|
|
||||||
|
|
||||||
To distribute a theme, simply export the object in your package entry. To consume an external theme, import and re-export it from the custom theme entry:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import Theme from 'awesome-vitepress-theme'
|
|
||||||
|
|
||||||
export default Theme
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extending the Default Theme
|
|
||||||
|
|
||||||
If you want to extend and customize the default theme, you can import it from `vitepress/theme` and augment it in a custom theme entry. Here are some examples of common customizations:
|
|
||||||
|
|
||||||
### Registering Global Components
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import DefaultTheme from 'vitepress/theme'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...DefaultTheme,
|
|
||||||
enhanceApp(ctx) {
|
|
||||||
// extend default theme custom behaviour.
|
|
||||||
DefaultTheme.enhanceApp(ctx)
|
|
||||||
|
|
||||||
// register your custom global components
|
|
||||||
ctx.app.component('MyGlobalComponent' /* ... */)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Since we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.
|
|
||||||
|
|
||||||
### Customizing CSS
|
|
||||||
|
|
||||||
The default theme CSS is customizable by overriding root level CSS variables:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import DefaultTheme from 'vitepress/theme'
|
|
||||||
import './custom.css'
|
|
||||||
|
|
||||||
export default DefaultTheme
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
/* .vitepress/theme/custom.css */
|
|
||||||
:root {
|
|
||||||
--vp-c-brand: #646cff;
|
|
||||||
--vp-c-brand-light: #747bff;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See [default theme CSS variables](https://github.com/vuejs/vitepress/blob/main/src/clien/reference/default-theme-default/styles/vars.css) that can be overridden.
|
|
||||||
|
|
||||||
### Layout Slots
|
|
||||||
|
|
||||||
The default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import DefaultTheme from 'vitepress/theme'
|
|
||||||
import MyLayout from './MyLayout.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...DefaultTheme,
|
|
||||||
// override the Layout with a wrapper component that
|
|
||||||
// injects the slots
|
|
||||||
Layout: MyLayout
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<!--.vitepress/theme/MyLayout.vue-->
|
|
||||||
<script setup>
|
|
||||||
import DefaultTheme from 'vitepress/theme'
|
|
||||||
|
|
||||||
const { Layout } = DefaultTheme
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Layout>
|
|
||||||
<template #aside-outline-before>
|
|
||||||
My custom sidebar top content
|
|
||||||
</template>
|
|
||||||
</Layout>
|
|
||||||
</template>
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you could use render function as well.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// .vitepress/theme/index.js
|
|
||||||
import { h } from 'vue'
|
|
||||||
import DefaultTheme from 'vitepress/theme'
|
|
||||||
import MyComponent from './MyComponent.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...DefaultTheme,
|
|
||||||
Layout() {
|
|
||||||
return h(DefaultTheme.Layout, null, {
|
|
||||||
'aside-outline-before': () => h(MyComponent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Full list of slots available in the default theme layout:
|
|
||||||
|
|
||||||
- When `layout: 'doc'` (default) is enabled via frontmatter:
|
|
||||||
- `doc-footer-before`
|
|
||||||
- `doc-before`
|
|
||||||
- `doc-after`
|
|
||||||
- `sidebar-nav-before`
|
|
||||||
- `sidebar-nav-after`
|
|
||||||
- `aside-top`
|
|
||||||
- `aside-bottom`
|
|
||||||
- `aside-outline-before`
|
|
||||||
- `aside-outline-after`
|
|
||||||
- `aside-ads-before`
|
|
||||||
- `aside-ads-after`
|
|
||||||
- When `layout: 'home'` is enabled via frontmatter:
|
|
||||||
- `home-hero-before`
|
|
||||||
- `home-hero-info`
|
|
||||||
- `home-hero-image`
|
|
||||||
- `home-hero-after`
|
|
||||||
- `home-features-before`
|
|
||||||
- `home-features-after`
|
|
||||||
- Always:
|
|
||||||
- `layout-top`
|
|
||||||
- `layout-bottom`
|
|
||||||
- `nav-bar-title-before`
|
|
||||||
- `nav-bar-title-after`
|
|
||||||
- `nav-bar-content-before`
|
|
||||||
- `nav-bar-content-after`
|
|
||||||
- `nav-screen-content-before`
|
|
||||||
- `nav-screen-content-after`
|
|
||||||
|
@ -0,0 +1,220 @@
|
|||||||
|
# Extending the Default Theme
|
||||||
|
|
||||||
|
VitePress comes with its default theme providing many features out of the box. You can check out the full features in the [Default Theme Config Overview](/reference/default-theme-config).
|
||||||
|
|
||||||
|
There are several cases where you may want to extend the default theme:
|
||||||
|
|
||||||
|
1. You want to modify the Vue app, for example register global components;
|
||||||
|
2. You want to tweak the CSS styling;
|
||||||
|
3. You want to inject custom content into the theme via layout slots.
|
||||||
|
|
||||||
|
## Using a Custom Theme
|
||||||
|
|
||||||
|
You can enable a custom theme by adding the `.vitepress/theme/index.js` or `.vitepress/theme/index.ts` file (the "theme entry file").
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├─ docs
|
||||||
|
│ ├─ .vitepress
|
||||||
|
│ │ ├─ theme
|
||||||
|
│ │ │ └─ index.js
|
||||||
|
│ │ └─ config.js
|
||||||
|
│ └─ index.md
|
||||||
|
└─ package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
A VitePress custom theme is simply an object containing four properties and is defined as follows:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface Theme {
|
||||||
|
Layout: Component // Vue 3 component
|
||||||
|
NotFound?: Component
|
||||||
|
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
|
||||||
|
setup?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EnhanceAppContext {
|
||||||
|
app: App // Vue 3 app instance
|
||||||
|
router: Router // VitePress router instance
|
||||||
|
siteData: Ref<SiteData>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The theme entry file should export the theme as its default export:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import Layout from './Layout.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// root component to wrap each page
|
||||||
|
Layout,
|
||||||
|
|
||||||
|
// this is a Vue 3 functional component
|
||||||
|
NotFound: () => 'custom 404',
|
||||||
|
|
||||||
|
enhanceApp({ app, router, siteData }) {
|
||||||
|
// app is the Vue 3 app instance from `createApp()`.
|
||||||
|
// router is VitePress' custom router. `siteData` is
|
||||||
|
// a `ref` of current site-level metadata.
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
// this function will be executed inside VitePressApp's
|
||||||
|
// setup hook. all composition APIs are available here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
...where the `Layout` component could look like this:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- .vitepress/theme/Layout.vue -->
|
||||||
|
<template>
|
||||||
|
<h1>Custom Layout!</h1>
|
||||||
|
|
||||||
|
<!-- this is where markdown content will be rendered -->
|
||||||
|
<Content />
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
The default export is the only contract for a custom theme. Inside your custom theme, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./using-vue#browser-api-access-restrictions).
|
||||||
|
|
||||||
|
To distribute a theme, simply export the object in your package entry. To consume an external theme, import and re-export it from the custom theme entry:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import Theme from 'awesome-vitepress-theme'
|
||||||
|
|
||||||
|
export default Theme
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending the Default Theme
|
||||||
|
|
||||||
|
If you want to extend and customize the default theme, you can import it from `vitepress/theme` and augment it in a custom theme entry. Here are some examples of common customizations:
|
||||||
|
|
||||||
|
## Registering Global Components
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...DefaultTheme,
|
||||||
|
enhanceApp(ctx) {
|
||||||
|
// extend default theme custom behaviour.
|
||||||
|
DefaultTheme.enhanceApp(ctx)
|
||||||
|
|
||||||
|
// register your custom global components
|
||||||
|
ctx.app.component('MyGlobalComponent' /* ... */)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Since we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.
|
||||||
|
|
||||||
|
## Customizing CSS
|
||||||
|
|
||||||
|
The default theme CSS is customizable by overriding root level CSS variables:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import './custom.css'
|
||||||
|
|
||||||
|
export default DefaultTheme
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* .vitepress/theme/custom.css */
|
||||||
|
:root {
|
||||||
|
--vp-c-brand: #646cff;
|
||||||
|
--vp-c-brand-light: #747bff;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [default theme CSS variables](https://github.com/vuejs/vitepress/blob/main/src/clien/reference/default-theme-default/styles/vars.css) that can be overridden.
|
||||||
|
|
||||||
|
## Layout Slots
|
||||||
|
|
||||||
|
The default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import MyLayout from './MyLayout.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...DefaultTheme,
|
||||||
|
// override the Layout with a wrapper component that
|
||||||
|
// injects the slots
|
||||||
|
Layout: MyLayout
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!--.vitepress/theme/MyLayout.vue-->
|
||||||
|
<script setup>
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
|
||||||
|
const { Layout } = DefaultTheme
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Layout>
|
||||||
|
<template #aside-outline-before>
|
||||||
|
My custom sidebar top content
|
||||||
|
</template>
|
||||||
|
</Layout>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you could use render function as well.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// .vitepress/theme/index.js
|
||||||
|
import { h } from 'vue'
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import MyComponent from './MyComponent.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...DefaultTheme,
|
||||||
|
Layout() {
|
||||||
|
return h(DefaultTheme.Layout, null, {
|
||||||
|
'aside-outline-before': () => h(MyComponent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Full list of slots available in the default theme layout:
|
||||||
|
|
||||||
|
- When `layout: 'doc'` (default) is enabled via frontmatter:
|
||||||
|
- `doc-footer-before`
|
||||||
|
- `doc-before`
|
||||||
|
- `doc-after`
|
||||||
|
- `sidebar-nav-before`
|
||||||
|
- `sidebar-nav-after`
|
||||||
|
- `aside-top`
|
||||||
|
- `aside-bottom`
|
||||||
|
- `aside-outline-before`
|
||||||
|
- `aside-outline-after`
|
||||||
|
- `aside-ads-before`
|
||||||
|
- `aside-ads-after`
|
||||||
|
- When `layout: 'home'` is enabled via frontmatter:
|
||||||
|
- `home-hero-before`
|
||||||
|
- `home-hero-info`
|
||||||
|
- `home-hero-image`
|
||||||
|
- `home-hero-after`
|
||||||
|
- `home-features-before`
|
||||||
|
- `home-features-after`
|
||||||
|
- Always:
|
||||||
|
- `layout-top`
|
||||||
|
- `layout-bottom`
|
||||||
|
- `nav-bar-title-before`
|
||||||
|
- `nav-bar-title-after`
|
||||||
|
- `nav-bar-content-before`
|
||||||
|
- `nav-bar-content-after`
|
||||||
|
- `nav-screen-content-before`
|
||||||
|
- `nav-screen-content-after`
|
||||||
|
|
Loading…
Reference in new issue