Code Tree
Code tree plugin for rendering code structures with a file tree sidebar in Markdown, supporting file switching.
This plugin depends on the File Tree plugin for the file tree sidebar components.
Installation
pnpm add vitepress-plugin-code-treenpm install vitepress-plugin-code-treebun add vitepress-plugin-code-treedeno add vitepress-plugin-code-treeyarn add vitepress-plugin-code-treeUsage
vitepress-tuck Mode Recommended
import { defineConfig } from 'vitepress-tuck'
import codeTree from 'vitepress-plugin-code-tree'
export default defineConfig({
plugins: [codeTree()],
})Learn more about vitepress-tuck
Native Mode
import { defineConfig } from 'vitepress'
import { codeTreeMarkdownPlugin } from 'vitepress-plugin-code-tree'
export default defineConfig({
markdown: {
config: (md) => {
md.use(codeTreeMarkdownPlugin)
},
},
})import type { Theme } from 'vitepress'
import { enhanceAppWithCodeTree } from 'vitepress-plugin-code-tree/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCodeTree(ctx)
},
} satisfies ThemeSyntax
The plugin provides two syntaxes to render a code tree: a container syntax for inline file content, and an embed syntax to load files from a directory.
Container Syntax
Use the ::: code-tree container with fenced code blocks inside. Each fence must declare a filename via the [filename] syntax in its info string.
::: code-tree title="Project Structure"
```ts [index.ts]
const a = 1
```
```rs [main.rs]
fn main() {
println!("Hello, world!");
}
```
:::Container Attributes
| Attribute | Description | Default |
|---|---|---|
title | Code tree title | - |
height | Code tree container height | 420px |
entry | Entry file, opened by default | - |
show-sidebar | Show sidebar by default | false |
Active File
Add :active to a fence's info string to mark it as the default active file:
::: code-tree
```ts [index.ts] :active
const a = 1
```
```ts [utils.ts]
export const noop = () => {}
```
:::Embed Syntax
Use @[code-tree](dir) to embed a directory as a code tree. Files in the directory are loaded and rendered automatically.
@[code-tree](./src)The dir supports the following prefixes:
| Prefix | Description |
|---|---|
@ | Relative to VitePress srcDir |
/ | Relative to VitePress project root |
| - | Relative to the current markdown file's directory |
Embed Attributes
@[code-tree title="Source" height="500px" entry="index.ts" show-sidebar=true](./src)Configuration
CodeTreePluginOptions
interface CodeTreePluginOptions {
/**
* Default code tree container height
* @default '420px'
*/
height?: string | number
/**
* Glob patterns to ignore files
* Applied when loading files from a directory via the embed syntax
* node_modules and .DS_Store are always ignored
* @default []
*/
ignores?: string[]
/**
* File loaders
* Used to load resource files when embedding a directory with `@[code-tree](dir)`
* Custom loaders are merged before the built-in ones, so they take precedence
* @default []
*/
loaders?: CodeTreeFileLoader[]
}File Loaders
Loaders are used by the embed syntax to load file content. The plugin ships with built-in loaders for common file types, and custom loaders are merged before the built-in ones, so they take precedence.
Built-in loaders cover the following file types:
- Dot files (
.git*,.env*,.*ignore,.npmrc): Rendered as plain text .XXXrcconfig files (e.g..eslintrc): Rendered as JSON- Image files: Rendered as
<img>tags with propersrcresolution - Source files supported by Shiki: Rendered as fenced code blocks with syntax highlighting
import codeTree, { loadCodeContent } from 'vitepress-plugin-code-tree'
import { defineConfig } from 'vitepress-tuck'
export default defineConfig({
plugins: [
codeTree({
height: '500px',
ignores: ['**/*.test.ts'],
loaders: [
{
filter: ['**/*.md'],
load: (file) => loadCodeContent(file, 'md'),
},
],
}),
],
})The filter field accepts a glob pattern string, an array of glob patterns, or a predicate function that receives a CodeTreeFile and returns a boolean.
Example
Container Syntax
:::code-tree title="Code Tree" show-sidebar
```ts [index.ts]
const a = 1
```
```rs [main.rs]
fn main() {
println!("Hello, world!");
}
```
:::Code Tree
index.ts
main.rs
const a = 1fn main() {
println!("Hello, world!");
}Embed Syntax
@[code-tree title="Code Tree" show-sidebar](@/en)Code Tree
api.md
plugin-dev.md
quick-start.md
toolkit.md
wrap-plugin.md
abbr.md
annotation.md
caniuse.md
code-collapse.md
code-tree.md
codepen.md
collapse.md
field.md
file-tree.md
icons.md
intro.md
jsfiddle.md
mark.md
mermaid.md
npm-to.md
obsidian.md
pdf.md
plantuml.md
plot.md
qrcode.md
repo-card.md
stackblitz.md
steps.md
video.md
watermark.md
index.md
# API Reference
<NpmBadge name="vitepress-tuck" />
## vitepress-tuck
### defineConfig
`defineConfig` is the core function of `vitepress-tuck`, used as a replacement for VitePress's `defineConfig`.
```ts
import { defineConfig } from 'vitepress-tuck'
function defineConfig<ThemeConfig = DefaultTheme.Config>(
config: UserConfig<NoInfer<ThemeConfig>> & TuckConfig,
): UserConfig<NoInfer<ThemeConfig>>
```
#### Parameters
| Parameter | Type | Description |
| --------- | ------------------------- | -------------------------------------------- |
| `config` | `UserConfig & TuckConfig` | VitePress original config + `plugins` option |
`TuckConfig` definition:
```ts
interface TuckConfig {
/**
* vitepress plugin list
*/
plugins?: VitepressPlugin[]
/**
* Options for the unplugin-vue-components plugin.
*
* @see - https://github.com/unplugin/unplugin-vue-components
*/
components?: ComponentsOptions
}
```
#### Return Value
Returns the merged and complete VitePress `UserConfig` object.
#### How It Works
1. Iterates through the `plugins` array, merging each plugin's `markdown`, `vite`, `vue` and other configurations.
2. Collects all hooks (`buildEnd`, `transformHead`, `transformHtml`, `transformPageData`, `postRender`)
and merges them according to their respective strategies:
- `markdown.config`, `buildEnd` → concurrent execution
- `transformHead` → concurrent execution with result merging
- `transformHtml`, `transformPageData`, `postRender` → sequential execution, chained
3. Injects the `client` configuration from plugins into the built-in `virtual-enhance-app` virtual module.
4. Collects `componentResolver` declarations from plugins into the built-in `unplugin-vue-components` resolver list.
5. Finally merges the user's own configuration.
---
### definePlugin
Used to define VitePress plugins. It is a type helper function that helps developers create plugins in a standardized way.
```ts
import { definePlugin } from 'vitepress-tuck'
function definePlugin<T>(
plugin: (option?: T) => VitepressPlugin,
): (option?: T) => VitepressPlugin
```
#### Parameters
| Parameter | Type | Description |
| --------- | --------------------------------- | --------------------------------------------------------------------------- |
| `plugin` | `(option?: T) => VitepressPlugin` | Plugin factory function, receives optional options, returns a plugin object |
---
### VitepressPlugin
Type definition for plugin objects:
```ts
interface VitepressPlugin extends Pick<
UserConfig,
'markdown' | 'vite' | 'vue' | 'buildEnd' | 'transformHead' | 'transformHtml' | 'transformPageData' | 'postRender'
> {
/**
* Plugin name (required, for identification and debugging)
*/
name: string
/**
* Client configuration, automatically injected into virtual:enhance-app
*/
client?: {
/**
* Custom import statement list
*
* @example
* ```ts
* imports: ['import "my-plugin/style.css"']
* ```
*/
imports?: string[]
/**
* Client-side enhance function name.
* - Not set: no enhanceApp function is injected
* - true: default function name is `enhanceApp`
* - string: the specified function name
*
* @example
* ```ts
* enhance: 'enhanceAppWithMyPlugin'
* ```
*/
enhance?: string | boolean
}
/**
* Component resolvers for unplugin-vue-components auto-import.
*
* - String array: declared component names are resolved from `<plugin-name>/client`
* - ComponentResolver object: custom resolve logic
*
* @example
* ```ts
* // Simple form
* componentResolver: ['MyComponent', 'OtherComponent']
* ```
*/
componentResolver?: string[] | ComponentResolver
}
```
#### Supported VitePress Configuration Options
| Property | Type | Description |
| ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `markdown` | `UserConfig['markdown']` | Markdown-related configuration, commonly used with `markdown.config` to register markdown-it plugins |
| `vite` | `UserConfig['vite']` | Vite configuration, for registering Vite plugins and optimization options |
| `vue` | `UserConfig['vue']` | Vue application-level configuration |
| `buildEnd` | `UserConfig['buildEnd']` | Build completion hook (concurrent) |
| `transformHead` | `UserConfig['transformHead']` | HTML head transform hook (concurrent, results merged) |
| `transformHtml` | `UserConfig['transformHtml']` | HTML content transform hook (sequential, chained) |
| `transformPageData` | `UserConfig['transformPageData']` | Page data transform hook (sequential, chained) |
| `postRender` | `UserConfig['postRender']` | Post-render hook (sequential, chained) |
---
### virtual:enhance-app
`virtual:enhance-app` is a virtual module provided by `vitepress-tuck`.
It automatically collects all plugins' `client` configurations and generates the corresponding code.
Import it in the theme entry:
```ts [.vitepress/theme/index.ts]
import enhanceApp from 'virtual:enhance-app'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceApp(ctx)
},
}
```
TypeScript support requires adding the type reference:
```json [tsconfig.json]
{
"compilerOptions": {
"types": ["vitepress-tuck/client-types"]
}
}
```
---
### Built-in Plugin: auto-components
`vitepress-tuck` integrates [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components) as
a built-in plugin, providing automatic on-demand component importing. This plugin is enabled by default — no manual registration required.
#### Default Behavior
- Scans `.vue` and `.md` files for component usage
- Generates type declarations at `node_modules/.vite/components.d.ts`
- Automatically collects `componentResolver` declarations from all plugins
#### Custom Configuration
Customize `unplugin-vue-components` behavior via the `components` option in `defineConfig`:
```ts
import { defineConfig } from 'vitepress-tuck'
export default defineConfig({
components: {
// Custom scan directories
dirs: ['src/components'],
// Use directory as namespace
directoryAsNamespace: true,
// Other unplugin-vue-components options...
},
plugins: [],
})
```
::: tip
Plugin `componentResolver` declarations are merged with the user's `components` configuration.
Plugin developers only need to declare `componentResolver` in their plugin,
and users can use the corresponding components directly in Markdown or Vue files without manual imports.
:::# Plugin Development
<NpmBadge name="vitepress-tuck" />
`vitepress-tuck` provides the `definePlugin` function to help developers easily create VitePress plugins.
With `definePlugin`, you can centralize options like `markdown`, `vite`, and `vue` — which would
otherwise require scattered configuration by users — into a single plugin function.
## Basic Structure
A plugin based on `vitepress-tuck` consists of the following parts:
```ts
import { definePlugin } from 'vitepress-tuck'
export default definePlugin((options?: MyPluginOptions) => ({
name: 'vitepress-plugin-my-plugin',
// Client configuration: auto-injected into virtual:enhance-app
client: {
imports: [],
enhance: 'enhanceAppWithMyPlugin',
},
// Component resolver: declare plugin components for auto on-demand import
componentResolver: ['MyComponent', 'OtherComponent'],
// Markdown configuration: register markdown-it plugins
markdown: {
config: (md) => {
md.use(myMarkdownPlugin, options?.markdownOptions)
},
},
// Vite configuration
vite: {
plugins: [myVitePlugin(options?.viteOptions)],
},
// Other VitePress hooks
buildEnd: (site) => { /* ... */ },
transformHead: (ctx) => { /* ... */ },
transformHtml: (code, id, ctx) => { /* ... */ },
transformPageData: (pageData, ctx) => { /* ... */ },
postRender: (context) => { /* ... */ },
}))
```
## Core Concepts
### name
Each plugin must have a unique `name` for identification and debugging:
```ts
{
name: 'vitepress-plugin-my-plugin'
}
```
### client
The `client` configuration is used to inject code into the client side. `vitepress-tuck` automatically
injects this code into the `virtual:enhance-app` virtual module.
#### client.imports
Add custom import statements, commonly used for importing style files:
```ts
{
client: {
imports: [
'import "vitepress-plugin-my-plugin/style.css"',
],
}
}
```
#### client.enhance
Specifies the client-side enhance function name. This function will be called within the VitePress theme's `enhanceApp(ctx)`.
- When set to `true`, the default function name is `enhanceApp`
- When set to a string, that string is the function name
```ts
{
client: {
enhance: 'enhanceAppWithMyPlugin',
}
}
```
Correspondingly, export a function with the same name in the plugin's client entry file:
```ts
// client/index.ts
import type { EnhanceAppContext } from 'vitepress'
export function enhanceAppWithMyPlugin({ app }: EnhanceAppContext) {
// Register components, directives, etc.
app.component('MyComponent', MyComponent)
}
```
### componentResolver
The `componentResolver` declares the Vue components a plugin provides, enabling automatic on-demand import via
the built-in `unplugin-vue-components`. Users can use component names directly in Markdown or Vue files without manual imports.
#### String Array Form
The simplest form is an array of component names — they are resolved from `<plugin-name>/client`:
```ts
{
name: 'vitepress-plugin-my-plugin',
componentResolver: ['MyComponent', 'OtherComponent'],
}
```
Correspondingly, export these components in the plugin's client entry:
```ts
// client/index.ts
import MyComponent from './components/MyComponent.vue'
import OtherComponent from './components/OtherComponent.vue'
export { MyComponent, OtherComponent }
```
#### Custom ComponentResolver
For more complex resolution logic, pass a `ComponentResolver` object from `unplugin-vue-components`:
```ts
import type { ComponentResolver } from 'unplugin-vue-components'
const myResolver: ComponentResolver = {
type: 'component',
resolve: (name) => {
if (name.startsWith('My')) {
return { name, from: 'vitepress-plugin-my-plugin/client' }
}
},
}
export default definePlugin(() => ({
name: 'vitepress-plugin-my-plugin',
componentResolver: myResolver,
}))
```
::: tip
When a plugin uses both `client.enhance` for component registration and `componentResolver`,
prefer `componentResolver` for on-demand importing to reduce unnecessary component bundling.
:::
### markdown
Configure markdown-it plugins to extend Markdown syntax:
```ts
{
markdown: {
config: (md) => {
// Register custom containers
md.use(containerPlugin)
// Register inline rules
md.inline.ruler.before('emphasis', 'my_rule', myRule)
},
}
}
```
### vite
Configure Vite plugins and optimization options:
```ts
{
vite: {
plugins: [myVitePlugin()],
ssr: {
noExternal: ['my-plugin-package'],
},
}
}
```
### Hooks
`definePlugin` supports various VitePress lifecycle hooks:
| Hook | Description | Execution |
| ------------------- | ------------------------------ | -------------------------- |
| `buildEnd` | Triggered on build completion | Concurrent |
| `transformHead` | Transforms HTML head | Concurrent, results merged |
| `transformHtml` | Transforms HTML content | Sequential, chained |
| `transformPageData` | Transforms page data | Sequential, chained |
| `postRender` | Triggered after page rendering | Sequential, chained |
## Client Code Organization
When a plugin needs to provide client-side code (e.g., Vue components), the recommended directory structure is:
::: file-tree title="my-plugin"
- my-plugin
- src
- client
- components
- MyComponent.vue
- index.ts # Export enhanceApp function
- node
- myPlugin.ts # Plugin core logic
- index.ts # Plugin entry, using definePlugin
- package.json
- tsconfig.json
:::
Configure `exports` in `package.json` to export client code separately:
```json
{
"exports": {
".": {
"types": "./dist/node/index.d.ts",
"default": "./dist/node/index.js"
},
"./client": {
"browser": "./dist/client/browser/index.js",
"default": "./dist/client/ssr/index.js"
}
}
}
```
## Recommended: vitepress-plugin-toolkit
`vitepress-plugin-toolkit` provides a rich set of utility functions to assist plugin development, including:
- `createContainerPlugin` — Create markdown-it custom containers
- `createContainerSyntaxPlugin` — Create custom syntax containers
- `createEmbedRuleBlock` — Create embed syntax blocks
- `resolveAttrs` / `stringifyAttrs` — Attribute parsing and serialization
- `createLogger` — Logging utility
- `createLocales` — Internationalization support
- `useSize` — Responsive size calculation
See the [Toolkit API documentation](./toolkit) for details.
## Complete Example
Here is a simple step plugin built with `definePlugin`:
```ts [node/index.ts]
import { definePlugin } from 'vitepress-tuck'
import { createContainerPlugin } from 'vitepress-plugin-toolkit'
export const stepsPlugin = (md) => {
createContainerPlugin(md, 'steps', {
before: () => '<div class="vp-steps">',
})
}
export default definePlugin(() => ({
name: 'vitepress-plugin-steps',
client: {
imports: ['import "vitepress-plugin-steps/style.css"'],
},
markdown: {
config: (md) => {
md.use(stepsPlugin)
},
},
}))
```
Users simply need to:
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import steps from 'vitepress-plugin-steps'
export default defineConfig({
plugins: [steps()],
})
```# Quick Start
## What is vitepress-tuck?
`vitepress-tuck` provides simple, flexible, and low-barrier plugin development and integration capabilities
for VitePress. It wraps VitePress's `defineConfig` to provide an additional `plugins` option, shifting the
complexity of plugin integration into the plugins themselves, so users only need to add plugins to the `plugins` array.
## Installation
::: npm-to
```sh
npm install vitepress vitepress-tuck
```
:::
## Using in a VitePress Site
::: steps
- ### Replace the Configuration File
Replace `defineConfig` in `.vitepress/config.ts` with `vitepress-tuck`'s `defineConfig`:
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { defineConfig } from 'vitepress-tuck' // [!code ++]
export default defineConfig({
plugins: [
// Add plugins here
],
// Other VitePress config options ...
})
```
- ### Configure the Client Entry
Import `virtual:enhance-app` in `.vitepress/theme/index.ts`:
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import enhanceApp from 'virtual:enhance-app'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceApp(ctx) // [!code ++]
},
} satisfies Theme
```
`virtual:enhance-app` is a virtual module. `vitepress-tuck` automatically injects plugin client code into it — no manual configuration required.
- ### TypeScript Support
If your project uses TypeScript, add the type reference in `tsconfig.json`:
```json
{
"compilerOptions": {
"types": ["vitepress-tuck/client-types"]
}
}
```
:::
## Using Plugins
Using plugins is simple — just import and invoke them in the `plugins` array:
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import steps from 'vitepress-plugin-steps'
import mermaid from 'vitepress-plugin-mermaid-tuck'
export default defineConfig({
plugins: [
steps(),
mermaid({
// Plugin options can be passed here
}),
],
})
```
Refer to each plugin's documentation for its configuration options.# Toolkit API
<NpmBadge name="vitepress-plugin-toolkit" />
`vitepress-plugin-toolkit` is a VitePress plugin development toolkit that provides a rich set of utility functions to assist plugin development.
Installation:
::: npm-to
```sh
npm install vitepress-plugin-toolkit
```
:::
## Node-side API
Import from `vitepress-plugin-toolkit`:
```ts
import {
createContainerPlugin,
createContainerSyntaxPlugin,
createEmbedRuleBlock,
resolveAttrs,
resolveAttr,
stringifyAttrs,
createLogger,
createLocales,
getVitepressConfig,
getLocaleWithPath,
resolveRouteLink,
parseRect,
slugify,
treatAsHtml,
} from 'vitepress-plugin-toolkit'
```
---
### createContainerPlugin
Create a markdown-it custom container plugin. Used for processing `::: type` syntax, where content is parsed normally by markdown-it.
```ts
function createContainerPlugin(
md: MarkdownIt,
type: string,
options?: ContainerOptions,
): void
```
**ContainerOptions:**
```ts
interface ContainerOptions {
/**
* Callback for rendering container opening tag
*/
before?: (info: string, tokens: Token[], index: number, options: Options, env: any) => string
/**
* Callback for rendering container closing tag
*/
after?: (info: string, tokens: Token[], index: number, options: Options, env: any) => string
}
```
**Usage Example:**
```ts
import { createContainerPlugin } from 'vitepress-plugin-toolkit'
function myPlugin(md) {
createContainerPlugin(md, 'steps', {
before: () => '<div class="vp-steps">',
})
}
```
---
### createContainerSyntaxPlugin
Create a custom syntax container plugin. Unlike `createContainerPlugin`, the content is not parsed by markdown-it and must be handled manually.
```ts
function createContainerSyntaxPlugin(
md: MarkdownIt,
type: string,
render?: RenderRule,
): void
```
Raw content inside the container is accessible via `token.content`, and metadata via `token.meta`.
**Usage Example:**
```ts
import { createContainerSyntaxPlugin } from 'vitepress-plugin-toolkit'
function myPlugin(md) {
createContainerSyntaxPlugin(md, 'file-tree', (tokens, index) => {
const { content, meta } = tokens[index]
return `<div class="file-tree">${content}</div>`
})
}
```
---
### createEmbedRuleBlock
Create an embed rule block for handling `@[type ...](args)` syntax.
```ts
function createEmbedRuleBlock<Meta extends Record<string, any>>(
md: MarkdownIt,
options: EmbedRuleBlockOptions<Meta>,
): void
```
**EmbedRuleBlockOptions:**
```ts
interface EmbedRuleBlockOptions<Meta extends Record<string, any>> {
/** Embed type, e.g. 'pdf', 'qrcode' */
type: string
/** Token name, defaults to type */
name?: string
/** Name of the rule to insert before, default 'code' */
beforeName?: string
/** Rule options */
ruleOptions?: RuleOptions
/** Parse the `info` and `source` in `@[type info](source)` and convert them into a metadata object. */
meta: (info: string, source: string) => Meta
/** Generate content from metadata */
content?: (meta: Meta, env: MarkdownEnv) => string
/** Render function */
render?: (tokens: Token[], index: number, env: MarkdownEnv) => string
}
```
**Usage Example:**
```ts
import { createEmbedRuleBlock } from 'vitepress-plugin-toolkit'
function myPlugin(md) {
createEmbedRuleBlock(md, {
type: 'pdf',
meta: (info, source) => ({
attrs: info,
src: source,
}),
content: (meta, env) => {
return `<VPPdf src="${meta.src}" ${meta.attrs} />`
},
})
}
```
---
### resolveAttrs
Parse an attribute string into an object.
```ts
function resolveAttrs<T extends Record<string, any> = Record<string, any>>(info: string): T
```
**Example:**
```ts
resolveAttrs('width="100%" height="400" dark')
// => { width: '100%', height: '400', dark: true }
```
---
### resolveAttr
Parse a single attribute value from an info string.
```ts
function resolveAttr(info: string, key: string): string | undefined
```
---
### stringifyAttrs
Serialize an attributes object into an HTML attribute string.
```ts
function stringifyAttrs<T extends object = object>(
attrs: T,
withUndefinedOrNull?: boolean,
forceStringify?: (keyof T)[],
): string
```
**Example:**
```ts
stringifyAttrs({ width: '100%', height: 400, dark: true })
// => ' width="100%" :height="400" dark'
```
---
### createLogger
Create a logger instance.
```ts
function createLogger(
prefix: string,
defaultLevel?: LogLevel,
): Logger
```
**LogLevel:**
```ts
type LogLevel = 'info' | 'warn' | 'error' | 'debug' | 'silent'
```
**Example:**
```ts
const logger = createLogger('my-plugin', 'info')
logger.info('Plugin loaded') // [my-plugin] Plugin loaded
logger.warn('Potential issue') // [my-plugin] Potential issue
logger.error('An error occurred') // [my-plugin] An error occurred
logger.debug('Debug info', true) // [my-plugin] Debug info
```
---
### createLocales
Create multi-language configuration, automatically matching VitePress's language settings.
```ts
function createLocales<LocaleData extends Record<string, unknown>>(
builtinLocales: BuiltinLocales<LocaleData>,
userLocales?: Record<string, LocaleData>,
): Record<string, LocaleData>
```
**Example:**
```ts
const locales = createLocales(
[
[['en', 'en-US'], { chart: 'Chart', source: 'Source' }],
[['zh', 'zh-CN'], { chart: '图表', source: '源码' }],
],
userLocales,
)
```
---
### getVitepressConfig
Get the current VitePress site configuration.
```ts
function getVitepressConfig(): SiteConfig
```
---
### getLocaleWithPath
Get language information based on a file path.
```ts
function getLocaleWithPath(path: string): { lang: string, locale: string }
```
---
### resolveRouteLink
Convert a relative path to a VitePress route link.
```ts
function resolveRouteLink(url: string, env: MarkdownEnv): string
```
---
### parseRect
Parse a size string, automatically appending a unit if a number is passed.
```ts
function parseRect(str: string, unit?: string): string
```
**Example:**
```ts
parseRect('400') // => '400px'
parseRect('50%') // => '50%'
parseRect('10', 'rem') // => '10rem'
```
---
### slugify
Convert a string to a URL-friendly slug format.
```ts
function slugify(str: string): string
```
---
### treatAsHtml
Determine whether a filename should be treated as HTML (non-known-resource extensions are treated as HTML).
```ts
function treatAsHtml(filename: string): boolean
```
---
## Client-side API
Import from `vitepress-plugin-toolkit/client`:
```ts
import {
VPCopyButton,
VPLoading,
useSize,
isiPhone,
isWindows,
isiPad,
isIOS,
isMacOS,
isMobile,
isSafari,
} from 'vitepress-plugin-toolkit/client'
```
### VPCopyButton
Copy button component.
```vue
<template>
<VPCopyButton :text="code" />
</template>
```
### VPLoading
Loading state component.
```vue
<template>
<VPLoading />
</template>
```
### useSize
Responsive size calculation composable.
```ts
function useSize<T extends HTMLElement>(
el: TemplateRef<T>,
options: ToRefs<SizeOptions>,
extraHeight?: MaybeRef<number>,
): {
width: Ref<string>
height: Ref<string>
resize: () => void
}
```
**SizeOptions:**
```ts
interface SizeOptions {
width?: string
height?: string
ratio?: number | string
}
```
### Device Detection Utilities
| Function | Description |
| -------- | ----------- |
| `isIPhone()` | Check if iPhone |
| `isIPad()` | Check if iPad |
| `isIOS()` | Check if iOS device |
| `isMacOS()` | Check if macOS |
| `isWindows()` | Check if Windows |
| `isMobile()` | Check if mobile device |
| `isSafari()` | Check if Safari browser |
---
## Shared Utilities
Can be imported from either `vitepress-plugin-toolkit` or `vitepress-plugin-toolkit/client`:
```ts
import { isExternal, isLinkWithProtocol } from 'vitepress-plugin-toolkit'
```
### isExternal
Check if a link is an external link.
```ts
function isExternal(path: string): boolean
```
### isLinkWithProtocol
Check if a link contains a protocol prefix.
```ts
function isLinkWithProtocol(link: string): boolean
```
---
## CSS Transition Animations
`vitepress-plugin-toolkit` provides predefined CSS transition animations that can be imported in plugins:
```css
@import 'vitepress-plugin-toolkit/styles/transition/fade-in.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-up.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-down.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-left.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-right.css';
@import 'vitepress-plugin-toolkit/styles/transition/slide-in-up.css';
@import 'vitepress-plugin-toolkit/styles/transition/slide-in-down.css';
@import 'vitepress-plugin-toolkit/styles/transition/slide-in-left.css';
@import 'vitepress-plugin-toolkit/styles/transition/slide-in-right.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-scale-up.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-width-expand.css';
@import 'vitepress-plugin-toolkit/styles/transition/fade-in-height-expand.css';
```# Wrapping Existing Plugins
If your VitePress site is already using plugins, or you have a plugin that hasn't been packaged
for `vitepress-tuck` mode, you can easily wrap it into a compatible form.
## Why Wrap?
Traditional VitePress plugins often require users to configure multiple locations:
```ts
// Traditional approach — configuration scattered across multiple places
import { defineConfig } from 'vitepress'
import { someMarkdownPlugin } from 'some-plugin'
export default defineConfig({
markdown: {
config: (md) => {
md.use(someMarkdownPlugin)
},
},
vite: {
plugins: [someVitePlugin()],
},
})
```
By wrapping into a `vitepress-tuck` plugin, users only need to add it to the `plugins` array — all
configuration is handled internally by the plugin.
## Wrapping Methods
### Wrapping with definePlugin
For any existing plugin logic, use `definePlugin` to wrap it:
```ts
import { definePlugin } from 'vitepress-tuck'
import { someMarkdownPlugin } from 'some-plugin'
import { someVitePlugin } from 'some-plugin/vite'
export default definePlugin((options?: MyOptions) => ({
name: 'vitepress-plugin-some-plugin',
markdown: {
config: (md) => {
md.use(someMarkdownPlugin, options)
},
},
vite: {
plugins: [someVitePlugin(options)],
},
}))
```
### Wrapping a Markdown-Only Plugin
If the plugin only involves a markdown-it extension, wrapping is very simple:
```ts
import { definePlugin } from 'vitepress-tuck'
export default definePlugin(() => ({
name: 'vitepress-plugin-my-plugin',
markdown: {
config: (md) => {
md.use(myMarkdownItPlugin)
},
},
}))
```
### Wrapping a Vite-Only Plugin
If the plugin only needs Vite configuration:
```ts
import { definePlugin } from 'vitepress-tuck'
import myVitePlugin from 'vite-plugin-my'
export default definePlugin((options?: MyOptions) => ({
name: 'vitepress-plugin-my-plugin',
vite: {
plugins: [myVitePlugin(options)],
},
}))
```
### Wrapping a Plugin That Requires Client Injection
If the plugin needs to inject components or styles on the client side, configure the `client` option:
```ts
import { definePlugin } from 'vitepress-tuck'
export default definePlugin(() => ({
name: 'vitepress-plugin-my-plugin',
client: {
imports: [
// Inject styles
'import "my-plugin/style.css"',
],
enhance: 'enhanceAppWithMyPlugin',
},
markdown: {
config: (md) => {
md.use(myMarkdownPlugin)
},
},
vite: {
ssr: {
// Ensure correct bundling during SSR
noExternal: ['my-plugin'],
},
},
}))
```
And export the enhance function in the client entry file:
```ts
// client/index.ts
import type { EnhanceAppContext } from 'vitepress'
import MyComponent from './components/MyComponent.vue'
export function enhanceAppWithMyPlugin({ app }: EnhanceAppContext) {
app.component('MyComponent', MyComponent)
}
```
## Real-World Example
Here's how to wrap `vitepress-plugin-group-icons` into a `vitepress-tuck` plugin:
```ts
import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons'
import { definePlugin } from 'vitepress-tuck'
export default definePlugin(() => ({
name: 'vitepress-plugin-group-icons',
client: {
imports: ['import \'virtual:group-icons.css\''],
},
markdown: {
config: (md) => {
md.use(groupIconMdPlugin)
},
},
vite: {
plugins: [
groupIconVitePlugin(),
],
ssr: {
noExternal: [
'vitepress-plugin-group-icons',
],
},
},
}))
```
## Maintaining Compatibility
Wrapped plugins can still be used independently (without `vitepress-tuck`). Simply provide both usage modes in the plugin's README:
```ts
// Method 1: vitepress-tuck mode (recommended)
import { defineConfig } from 'vitepress-tuck'
import myPlugin from 'my-plugin'
export default defineConfig({
plugins: [myPlugin()],
})
// Method 2: Native VitePress mode
import { defineConfig } from 'vitepress'
import { myPlugin } from 'my-plugin/raw'
export default defineConfig({
markdown: {
config: (md) => {
md.use(myPlugin)
},
},
})
```# Abbr
<NpmBadge name="vitepress-plugin-abbr" />
Abbreviation plugin that adds an interactive tooltip to abbreviations in Markdown, displaying the full description on hover or focus.
Forked and modified from [`markdown-it-abbr`](https://github.com/markdown-it/markdown-it-abbr).
## Installation
::: npm-to
```sh
npm install vitepress-plugin-abbr
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import abbr from 'vitepress-plugin-abbr'
export default defineConfig({
plugins: [abbr()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { abbrMarkdownPlugin } from 'vitepress-plugin-abbr'
export default defineConfig({
markdown: {
config: (md) => {
md.use(abbrMarkdownPlugin, {
HTML: 'HyperText Markup Language',
W3C: 'World Wide Web Consortium',
})
},
},
})
```
Register the component in the theme:
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithAbbr } from 'vitepress-plugin-abbr/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithAbbr(ctx)
},
} satisfies Theme
```
## Syntax
Define an abbreviation using the `*[ABBR]: Full description` syntax. Once defined,
every occurrence of the abbreviation throughout the document is automatically recognized
and rendered with an interactive tooltip.
```md
The HTML specification is maintained by the W3C.
*[HTML]: HyperText Markup Language
*[W3C]: World Wide Web Consortium
```
**Rendered Result:**
The HTML specification is maintained by the W3C.
*[HTML]: HyperText Markup Language
*[W3C]: World Wide Web Consortium
### Inline Markdown in Descriptions
The full description of an abbreviation supports inline Markdown syntax, such as bold, italic, links, and code.
```md
The **HTML** specification is maintained by the W3C.
*[HTML]: HyperText Markup Language
*[W3C]: World [Wide Web](https://www.w3.org/) Consortium
```
**Rendered Result:**
The **HTML** specification is maintained by the W3C.
*[HTML]: HyperText Markup Language
*[W3C]: World [Wide Web](https://www.w3.org/) Consortium
## Global Abbreviations
Instead of defining abbreviations inline in each Markdown file, you can provide a global preset of abbreviations
through the plugin options. When both a global definition and an inline definition exist for the same abbreviation,
the inline definition takes precedence.
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import abbr from 'vitepress-plugin-abbr'
export default defineConfig({
plugins: [
abbr({
HTML: 'HyperText Markup Language',
W3C: 'World Wide Web Consortium',
}),
],
})
```
With this configuration, every occurrence of `HTML` and `W3C` across all pages will be rendered as
abbreviations automatically, without needing to define them in each file.
## Examples
Hover over or focus the abbreviations below to see their full descriptions:
```md
HTML W3C API CSS
*[HTML]: HyperText Markup Language
*[W3C]: World Wide Web Consortium
*[API]: Application Programming Interface
*[CSS]: Cascading Style Sheets
```
HTML W3C API CSS
*[HTML]: HyperText Markup Language
*[W3C]: World Wide Web Consortium
*[API]: Application Programming Interface
*[CSS]: Cascading Style Sheets# Annotation
<NpmBadge name="vitepress-plugin-annotation" />
Annotation plugin that adds interactive annotation markers to Markdown content.
Clicking a marker reveals a popover displaying the annotation content.
Annotation content supports full block-level Markdown syntax.
A single label can be defined multiple times — all definitions are collected and displayed as separate items in the popover.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-annotation
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import annotation from 'vitepress-plugin-annotation'
export default defineConfig({
plugins: [annotation()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { annotationMarkdownPlugin } from 'vitepress-plugin-annotation'
export default defineConfig({
markdown: {
config: (md) => {
md.use(annotationMarkdownPlugin, {
HTML: 'HyperText Markup Language',
})
},
},
})
```
Register the component in the theme:
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithAnnotation } from 'vitepress-plugin-annotation/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithAnnotation(ctx)
},
} satisfies Theme
```
## Syntax
Define an annotation using the `[+label]: annotation content` syntax, then reference it anywhere in your document
with `[+label]`. The reference is rendered as a small interactive marker that, on click,
reveals a popover displaying the annotation content.
```md
The **four great classical novels** [+novels] of Chinese literature are widely known.
[+novels]: **Romance of the Three Kingdoms** — a historical novel set in the Three Kingdoms period.
```
**Rendered Result:**
The **four great classical novels** [+novels1] of Chinese literature are widely known.
[+novels1]: **Romance of the Three Kingdoms** — a historical novel set in the Three Kingdoms period.
### Block-level Markdown in Annotations
Annotation content supports full block-level Markdown syntax, including headings, paragraphs, lists, code blocks, and more.
```md
The framework is built on [+vue].
[+vue]:
## Vue
A progressive framework for building user interfaces.
- Reactive data binding
- Component-based architecture
- [Learn more](https://vuejs.org/)
```
### Multi-line Definitions
Annotation definitions can span multiple lines. Continuation lines must be indented by at least two spaces.
Empty lines within the indented block are preserved as part of the annotation content.
A non-indented content line (such as the next definition or a new paragraph) terminates the multi-line definition.
```md
This concept is explained in [+detail].
[+detail]:
This is the first paragraph of the annotation.
This is the second paragraph, separated by an empty line
but still part of the same annotation.
This line is not indented, so the annotation definition ends here.
```
### Multiple Definitions per Label
A single label can be defined multiple times. All definitions are collected and displayed as separate items
in the popover, allowing you to provide multiple pieces of related information for the same reference.
```md
JavaScript has multiple versions [+js].
[+js]: **ES2015 (ES6)** — Introduced classes, modules, arrow functions, and more.
[+js]: **ES2020** — Added optional chaining, nullish coalescing, and BigInt.
```
**Rendered Result:**
JavaScript has multiple versions [+js].
[+js]: **ES2015 (ES6)** — Introduced classes, modules, arrow functions, and more.
[+js]: **ES2020** — Added optional chaining, nullish coalescing, and BigInt.
## Global Annotations
Instead of defining annotations inline in each Markdown file, you can provide a global preset of annotations through the plugin options. This is useful for terms that should be annotated consistently across all pages.
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import annotation from 'vitepress-plugin-annotation'
export default defineConfig({
plugins: [
annotation({
HTML: 'HyperText Markup Language',
CSS: ['Cascading Style Sheets', 'A style sheet language used for describing the presentation of a document.'],
}),
],
})
```
Each global annotation value can be a string or an array of strings. When an array is provided, each element becomes a separate item in the popover, just like multiple inline definitions for the same label.
## Examples
Click the annotation markers below to see the full content:
```md
The **four great classical novels** [+novels] of Chinese literature are widely known.
[+novels]:
**Romance of the Three Kingdoms**
Set against the backdrop of the Three Kingdoms period, it depicts the political and military struggles among Wei, Shu, and Wu.
[+novels]:
**Journey to the West**
Tells the story of the Tang Monk and his three disciples on their journey to obtain Buddhist scriptures, filled with mythology and fantastical adventures.
[+novels]:
**Dream of the Red Chamber**
Set against the rise and fall of the four great families — Jia, Shi, Wang, and Xue — it depicts the love tragedy of Jia Baoyu and Lin Daiyu.
[+novels]:
**Water Margin**
Depicts the story of 108 outlaws led by Song Jiang who gathered at Mount Liang during the late Northern Song dynasty.
```
The **four great classical novels** [+novels] of Chinese literature are widely known.
[+novels]:
**Romance of the Three Kingdoms**
Set against the backdrop of the Three Kingdoms period, it depicts the political and military struggles among Wei, Shu, and Wu.
[+novels]:
**Journey to the West**
Tells the story of the Tang Monk and his three disciples on their journey to obtain Buddhist scriptures, filled with mythology and fantastical adventures.
[+novels]:
**Dream of the Red Chamber**
Set against the rise and fall of the four great families — Jia, Shi, Wang, and Xue — it depicts the love tragedy of Jia Baoyu and Lin Daiyu.
[+novels]:
**Water Margin**
Depicts the story of 108 outlaws led by Song Jiang who gathered at Mount Liang during the late Northern Song dynasty.# Can I Use
<NpmBadge name="vitepress-plugin-caniuse" />
Embed browser compatibility data from [caniuse.com](https://caniuse.com/), displaying browser support for CSS/JS features on the page.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-caniuse
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import caniuse from 'vitepress-plugin-caniuse'
export default defineConfig({
plugins: [caniuse()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { caniuseMarkdownPlugin } from 'vitepress-plugin-caniuse'
export default defineConfig({
markdown: {
config: (md) => {
md.use(caniuseMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithCaniuse } from 'vitepress-plugin-caniuse/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCaniuse(ctx)
},
} satisfies Theme
```
## Syntax
Use `@[caniuse]()` to embed browser compatibility data:
```md
@[caniuse](feature_name)
```
### Baseline Mode
Use baseline mode to display a feature support overview:
```md
@[caniuse baseline](feature_name)
```
### Custom Version Range
Use `{}` to specify a version range:
```md
@[caniuse{-2,4}](feature_name)
@[caniuse baseline{-3,2}](feature_name)
```
- `{past, future}`: past is the number of versions to look back, future is the number to look ahead
- Default is `{5, 2}` — 5 versions back, 2 versions forward
### Getting Feature Names
Search for the feature you want to display on [caniuse.com](https://caniuse.com/),
click the `#` on the left side of the card, and you'll get the feature name in the browser's address bar.
::: details Not sure which part is the feature name?
**Take CSS `grid` as an example**
Search for `grid` on caniuse.com, then click the `#` on the first card. The address bar will change to `https://caniuse.com/css-grid`.
The feature name is `css-grid`.
Verify here: <https://caniuse.com/?search=grid>
:::
## Examples
### Display browser support for the `fetch` feature
```md
@[caniuse](fetch)
```
@[caniuse](fetch)
### Display baseline for the `fetch` feature
```md
@[caniuse baseline](fetch)
```
@[caniuse baseline](fetch)# Code Collapse
<NpmBadge name="vitepress-plugin-code-collapse" />
Code block folding plugin that automatically collapses code blocks exceeding a specified number of lines, improving page readability.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-code-collapse
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import collapsedLines from 'vitepress-plugin-code-collapse'
export default defineConfig({
plugins: [
collapsedLines(),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { collapsedLinesMarkdownPlugin } from 'vitepress-plugin-code-collapse'
export default defineConfig({
markdown: {
config: (md) => {
md.use(collapsedLinesMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithCollapsedLines } from 'vitepress-plugin-code-collapse/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCollapsedLines(ctx)
},
} satisfies Theme
```
## Syntax
### Global Folding
When `options` is set to a number, or `true` (defaults to 15 lines), all code blocks exceeding that line count will be automatically folded.
### Per-Block Folding
Use the `:collapsed-lines={N}` syntax in the code block's info string to control individual blocks:
````md
```ts :collapsed-lines
// Folds using the default value (15 lines)
```
```ts :collapsed-lines=10
// Folds starting from line 10
```
````
## Configuration
```ts
/**
* Collapsed lines configuration
* - `true`: Fold when exceeding 15 lines
* - `number`: Fold when exceeding the specified line count
* - `false`: No global folding, allows per-block control (default)
* - `'disable'`: Fully disable the plugin
* @default 'false'
*/
type options = boolean | number | 'disable'
```
## Example
````md
```ts :collapsed-lines=10
const a1 = 1
const a2 = 2
const a3 = 1
const a4 = 1
const a5 = 1
const a6 = 2
const a7 = 1
const a8 = 1
const a9 = 1
const a10 = 2
const a11 = 1
const a12 = 1
```
````
```ts :line-numbers=1 :collapsed-lines=10
const a1 = 1
const a2 = 2
const a3 = 1
const a4 = 1
const a5 = 1
const a6 = 2
const a7 = 1
const a8 = 1
const a9 = 1
const a10 = 2
const a11 = 1
const a12 = 1
```# Code Tree
<NpmBadge name="vitepress-plugin-code-tree" />
Code tree plugin for rendering code structures with a file tree sidebar in Markdown, supporting file switching.
This plugin depends on the [File Tree](./file-tree.md) plugin for the file tree sidebar components.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-code-tree
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import codeTree from 'vitepress-plugin-code-tree'
export default defineConfig({
plugins: [codeTree()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { codeTreeMarkdownPlugin } from 'vitepress-plugin-code-tree'
export default defineConfig({
markdown: {
config: (md) => {
md.use(codeTreeMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithCodeTree } from 'vitepress-plugin-code-tree/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCodeTree(ctx)
},
} satisfies Theme
```
## Syntax
The plugin provides two syntaxes to render a code tree: a container syntax for inline file content,
and an embed syntax to load files from a directory.
### Container Syntax
Use the `::: code-tree` container with fenced code blocks inside.
Each fence must declare a filename via the `[filename]` syntax in its info string.
````md
::: code-tree title="Project Structure"
```ts [index.ts]
const a = 1
```
```rs [main.rs]
fn main() {
println!("Hello, world!");
}
```
:::
````
#### Container Attributes
| Attribute | Description | Default |
| -------------- | ----------------------------- | ------- |
| `title` | Code tree title | - |
| `height` | Code tree container height | `420px` |
| `entry` | Entry file, opened by default | - |
| `show-sidebar` | Show sidebar by default | `false` |
#### Active File
Add `:active` to a fence's info string to mark it as the default active file:
````md
::: code-tree
```ts [index.ts] :active
const a = 1
```
```ts [utils.ts]
export const noop = () => {}
```
:::
````
### Embed Syntax
Use `@[code-tree](dir)` to embed a directory as a code tree. Files in the directory are loaded and rendered automatically.
```md
@[code-tree](./src)
```
The `dir` supports the following prefixes:
| Prefix | Description |
| ------ | ------------------------------------------------- |
| `@` | Relative to VitePress `srcDir` |
| `/` | Relative to VitePress project root |
| - | Relative to the current markdown file's directory |
#### Embed Attributes
````md
@[code-tree title="Source" height="500px" entry="index.ts" show-sidebar=true](./src)
````
## Configuration
### CodeTreePluginOptions
```ts
interface CodeTreePluginOptions {
/**
* Default code tree container height
* @default '420px'
*/
height?: string | number
/**
* Glob patterns to ignore files
* Applied when loading files from a directory via the embed syntax
* node_modules and .DS_Store are always ignored
* @default []
*/
ignores?: string[]
/**
* File loaders
* Used to load resource files when embedding a directory with `@[code-tree](dir)`
* Custom loaders are merged before the built-in ones, so they take precedence
* @default []
*/
loaders?: CodeTreeFileLoader[]
}
```
### File Loaders
Loaders are used by the embed syntax to load file content. The plugin ships with built-in loaders for common file types,
and custom loaders are merged before the built-in ones, so they take precedence.
Built-in loaders cover the following file types:
- Dot files (`.git*`, `.env*`, `.*ignore`, `.npmrc`): Rendered as plain text
- `.XXXrc` config files (e.g. `.eslintrc`): Rendered as JSON
- Image files: Rendered as `<img>` tags with proper `src` resolution
- Source files supported by Shiki: Rendered as fenced code blocks with syntax highlighting
```ts
import codeTree, { loadCodeContent } from 'vitepress-plugin-code-tree'
import { defineConfig } from 'vitepress-tuck'
export default defineConfig({
plugins: [
codeTree({
height: '500px',
ignores: ['**/*.test.ts'],
loaders: [
{
filter: ['**/*.md'],
load: (file) => loadCodeContent(file, 'md'),
},
],
}),
],
})
```
The `filter` field accepts a glob pattern string, an array of glob patterns,
or a predicate function that receives a `CodeTreeFile` and returns a boolean.
## Example
### Container Syntax
````md
:::code-tree title="Code Tree" show-sidebar
```ts [index.ts]
const a = 1
```
```rs [main.rs]
fn main() {
println!("Hello, world!");
}
```
:::
````
:::code-tree title="Code Tree" show-sidebar
```ts [index.ts]
const a = 1
```
```rs [main.rs]
fn main() {
println!("Hello, world!");
}
```
:::
### Embed Syntax
```md
@[code-tree title="Code Tree" show-sidebar](@/en)
```
@[code-tree title="Code Tree" show-sidebar](@/en)# CodePen
<NpmBadge name="vitepress-plugin-codepen" />
Embed [CodePen](https://codepen.io/) projects into VitePress pages.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-codepen
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import codepen from 'vitepress-plugin-codepen'
export default defineConfig({
plugins: [codepen()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { codepenPlugin } from 'vitepress-plugin-codepen'
export default defineConfig({
markdown: {
config: (md) => {
md.use(codepenPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithCodepen } from 'vitepress-plugin-codepen/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCodepen(ctx)
},
} satisfies Theme
```
## Syntax
### Basic Usage
```md
@[codepen](user/slash)
```
### With Options
```md
@[codepen preview editable title="Example" height="400px" tab="css,result" theme="dark"](leimapapa/RwOZQOW)
```
### Attribute Reference
| Attribute | Type | Default | Description |
| ---------- | --------- | ---------- | ----------------------------------- |
| `title` | `string` | - | Title |
| `user` | `string` | - | CodePen username (parsed from link) |
| `slash` | `string` | - | Pen identifier (parsed from link) |
| `tab` | `string` | `'result'` | Default tab to display |
| `theme` | `string` | - | Theme |
| `preview` | `boolean` | `false` | Preview mode |
| `editable` | `boolean` | `false` | Editable mode |
| `width` | `string` | `'100%'` | Width |
| `height` | `string` | - | Height |
## Example
```md
@[codepen](leimapapa/RwOZQOW)
```
@[codepen](leimapapa/RwOZQOW)# Collapse
<NpmBadge name="vitepress-plugin-collapse" />
Collapse container plugin for creating collapsible content sections in Markdown, with support for accordion mode,
card style, and per-item expand control.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-collapse
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import collapse from 'vitepress-plugin-collapse'
export default defineConfig({
plugins: [collapse()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { collapseMarkdownPlugin } from 'vitepress-plugin-collapse'
export default defineConfig({
markdown: {
config: (md) => {
md.use(collapseMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithCollapse } from 'vitepress-plugin-collapse/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithCollapse(ctx)
},
} satisfies Theme
```
## Syntax
Use the `::: collapse` container with a list to create collapsible sections. Each
list item becomes a collapse panel: the first line is the title, and the
following indented content is the panel body.
### Basic
```md
::: collapse
- Title 1
Content 1
- Title 2
Content 2
:::
```
**Rendered Result:**
::: collapse
- Title 1
Content 1
- Title 2
Content 2
:::
### Accordion
Add `accordion` to enable accordion mode — only one item can be expanded at a
time; expanding a new item collapses all others. Use `expand` to expand the
first item by default when no explicit `:+` flag is set.
```md
::: collapse accordion expand
- Question 1
Answer 1
- Question 2
Answer 2
:::
```
**Rendered Result:**
::: collapse accordion expand
- Question 1
Answer 1
- Question 2
Answer 2
:::
### Card Style
Add `card` to render the container with a bordered, rounded card style. It can
be combined with `accordion`.
```md
::: collapse accordion card
- Question 1
Answer 1
- Question 2
Answer 2
:::
```
**Rendered Result:**
::: collapse accordion card
- Question 1
Answer 1
- Question 2
Answer 2
- Question 3
Answer 3
:::
### Per-item Expand Flag
Prefix a title with `:+` to expand an item, or `:-` to collapse it. In accordion
mode, only the first `:+` flag takes effect. Items without a flag follow the
container's `expand` attribute.
```md
::: collapse
- :+ Expanded by default
Content
- :- Collapsed by default
Content
- No flag, follows container expand attribute
Content
:::
```
**Rendered Result:**
::: collapse
- :+ Expanded by default
Content
- :- Collapsed by default
Content
- No flag, follows container expand attribute
Content
:::
## Container Attributes
| Attribute | Type | Description |
| ----------- | --------- | -------------------------------------------------------- |
| `accordion` | `boolean` | Enable accordion mode (only one item expanded at a time) |
| `card` | `boolean` | Render with card style (bordered and rounded) |
| `expand` | `boolean` | Default expanded state |
## Item Flags
| Flag | Description |
| ---- | ------------------------------------------------------------ |
| `:+` | Expand this item (only the first one wins in accordion mode) |
| `:-` | Collapse this item |# Field
<NpmBadge name="vitepress-plugin-field" />
Field container plugin for rendering structured API fields and properties documentation in Markdown,
with support for field grouping and JSDoc-style tag annotations.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-field
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import field from 'vitepress-plugin-field'
export default defineConfig({
plugins: [field()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { fieldMarkdownPlugin } from 'vitepress-plugin-field'
export default defineConfig({
markdown: {
config: (md) => {
md.use(fieldMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithField } from 'vitepress-plugin-field/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithField(ctx)
},
} satisfies Theme
```
## Syntax
Use the `::: field` container to document API fields and properties, with JSDoc-style tags for metadata.
### Basic Field
```md
::: field count
@type Number
@default 0
Total number of users.
:::
```
### Field Tags
Supported tags: `@name`, `@type`, `@default`, `@required`, `@deprecated`, `@optional`, `@description`.
```md
::: field userName
@type String
@required
Unique identifier for the user.
:::
::: field email
@type String
@optional
@default example@mail.com
Contact email address.
:::
::: field oldField
@type String
@deprecated
This field is deprecated, please use the new field instead.
:::
```
**Rendered Result:**
::: field userName
@type String
@required
Unique identifier for the user.
:::
::: field email
@type String
@optional
@default example@mail.com
Contact email address.
:::
::: field oldField
@type String
@deprecated
This field is deprecated, please use the new field instead.
:::
### Tag Reference
| Tag | Description |
| -------------- | -------------------------------------------------------------------- |
| `@name` | Override the field name (defaults to the name from `info`) |
| `@type` | Field type annotation |
| `@default` | Default value for the field |
| `@required` | Mark the field as required |
| `@optional` | Mark the field as optional |
| `@deprecated` | Mark the field as deprecated |
| `@description` | Explicit description text; any non-tag line also becomes description |
### Field Group
Use the `::: field-group` container to group related fields together.
```md
:::: field-group
::: field id
@type Number
@required
Unique identifier.
:::
::: field name
@type String
@optional
Display name.
:::
::: field createdAt
@type Date
@default Date.now()
Creation timestamp.
:::
::::
```
**Rendered Result:**
:::: field-group
::: field id
@type Number
@required
Unique identifier.
:::
::: field name
@type String
@optional
Display name.
:::
::: field createdAt
@type Date
@default Date.now()
Creation timestamp.
:::
::::
### Explicit Description
Use the `@description` tag to specify description text explicitly. Any non-tag lines are also automatically treated as description content.
```md
::: field count
@description Total number of users. This field represents the count of active users in the system.
@type Number
@default 0
:::
```# File Tree
<NpmBadge name="vitepress-plugin-file-tree" />
File tree display plugin for rendering file directory structures in Markdown.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-file-tree
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import fileTree from 'vitepress-plugin-file-tree'
export default defineConfig({
plugins: [fileTree()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { fileTreeMarkdownPlugin } from 'vitepress-plugin-file-tree'
export default defineConfig({
markdown: {
config: (md) => {
md.use(fileTreeMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithFileTree } from 'vitepress-plugin-file-tree/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithFileTree(ctx)
},
} satisfies Theme
```
## Syntax
### Container Syntax
Use the `::: file-tree` container to represent file hierarchy via indentation:
```md
::: file-tree title="Project Structure"
- src/
- components/
- Button.vue
- Nav.vue
- index.ts
- package.json
- tsconfig.json
:::
```
### Fenced Code Syntax
Alternatively, use a fenced code block with the `tree` or `file-tree` language identifier.
The content follows the output format of the `tree` command-line tool (using Unicode
box-drawing characters):
````md
```tree
.
├── src/
│ ├── components/
│ │ ├── Button.vue
│ │ └── Nav.vue
│ └── index.ts
├── package.json
└── tsconfig.json
```
````
This is especially useful when you already have a `tree` command output and want to
paste it directly into your Markdown without reformatting.
### Node Annotations
Both syntaxes support the following node annotations:
| Syntax | Description |
| -------------------- | ------------------------------------ |
| `**filename**` | Highlight/focus the file |
| `-- filename` | Mark as removed |
| `++ filename` | Mark as added |
| `filename # comment` | Add a comment |
| `folder/` | Mark as folder, collapsed by default |
| `…` | Ellipsis marker |
Container example with annotations:
```md
::: file-tree title="Changed Files"
- src/
- -- old-file.ts
- ++ new-file.ts
- **main.ts** # Core entry
- …
:::
```
Fenced code example with annotations:
````md
```tree
.
├── src/
│ ├── -- old-file.ts
│ ├── ++ new-file.ts
│ └── **main.ts** # Core entry
└── …
```
````
## Example
```md
::: file-tree
- docs
- .vitepress
- ++ config.ts
- -- page1.md
- index.md
- theme # A **theme** directory
- client
- components
- **Navbar.vue**
- composables
- useNavbar.ts
- styles
- navbar.css
- config.ts
- node/
- package.json
- pnpm-lock.yaml
- .gitignore
- README.md
- …
:::
```
::: file-tree
- docs
- .vitepress
- ++ config.ts
- -- page1.md
- index.md
- theme # A **theme** directory
- client
- components
- **Navbar.vue**
- composables
- useNavbar.ts
- styles
- navbar.css
- config.ts
- node/
- package.json
- pnpm-lock.yaml
- .gitignore
- README.md
- …
:::# Icons
<NpmBadge name="vitepress-plugin-icons" />
Icons plugin that uses a simple `::name::` syntax to inline icons from [Iconify](https://iconify.design/), [iconfont](https://www.iconfont.cn/), or [FontAwesome](https://fontawesome.com/) in Markdown.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-icons
```
:::
> When using Iconify, you also need to install [`@iconify/json`](https://www.npmjs.com/package/@iconify/json) or the specific icon collections you need.
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import icons from 'vitepress-plugin-icons'
export default defineConfig({
plugins: [icons()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
> [!WARNING]
> Due to the high complexity of plugin configuration, it is only recommended for use in `vitepress-tuck` mode.
## Syntax
Use `::` delimiters to insert an icon inline. The full syntax is:
```md
::name =size /color::
```
- `name` — Icon name. The format depends on the provider (see below).
- `=size` — Optional. Icon size. Supports `=widthxheight` (e.g. `=1.2emx1.5em`) or a single `=width` (e.g. `=1.2em`) which applies to both width and height.
- `/color` — Optional. Icon color, e.g. `/red` or `/#ff0000`.
You can also prefix the content with a provider name (`iconify`/`iconfont`/`fontawesome`) to override the default provider for a single icon, and append extra attributes for FontAwesome.
### Iconify
Icon names use the `collection:icon` format, e.g. `tdesign:logo-github-filled`.
```md
::tdesign:logo-github-filled::
::tdesign:logo-github-filled =36px::
::tdesign:logo-github-filled /#f00::
::tdesign:logo-github-filled =36px /#f00::
::skill-icons:vscode-dark =36px::
```
**Rendered Result:**
::tdesign:logo-github-filled::
::tdesign:logo-github-filled =36px::
::tdesign:logo-github-filled /#f00::
::tdesign:logo-github-filled =36px /#f00::
::skill-icons:vscode-dark =36px::
### iconfont
Icon names use the plain name (without the `icon-` prefix), e.g. `hot` resolves to `icon-hot`.
```md
::hot::
::hot =24px::
::hot =24px /#f00::
::iconfont hot =24px /#f00::
```
**Rendered Result:**
::iconfont hot::
::iconfont hot =24px::
::iconfont hot =24px /#f00::
::iconfont hot =24px /#f00::
### FontAwesome
Icon names use the plain name, e.g. `circle-user`. Extra attributes like `border`, `beat`, `rotate-90`, `2xl` are appended after the name and converted to `fa-*` classes.
```md
::circle-user::
::circle-user =1.2em /#fff::
::fontawesome circle-user::
::fontawesome circle-user border::
::fontawesome circle-user rotate-90::
::fontawesome circle-user beat::
::fontawesome circle-user 2xl beat::
```
**Rendered Result:**
::fontawesome circle-user 2xl::
::fontawesome circle-user rotate-90::
::fontawesome circle-user beat::
::fontawesome circle-user border::
::fontawesome circle-user 2xl beat::
## Configuration
The plugin accepts a single provider option, an array of provider options, or no options (defaults to Iconify). When multiple providers are configured, mark one with `default: true` to set the default provider used by the `::name::` syntax.
### Common Options
| Option | Type | Default | Description |
| --------- | ------------------------------------------ | ----------- | --------------------------------- |
| `provider`| `'iconify' \| 'iconfont' \| 'fontawesome'` | `'iconify'` | Icon provider |
| `default` | `boolean` | `false` | Use as the default provider |
| `color` | `string` | `''` | Default icon color |
| `size` | `string \| number` | `'1.2em'` | Default icon size |
### Iconify
Extends [`unplugin-icons`](https://github.com/unplugin/unplugin-icons) options and [`unplugin-icons/resolver`](https://github.com/unplugin/unplugin-icons#resolver) options.
```ts [.vitepress/config.ts]
icons({
provider: 'iconify',
default: true,
size: '1.2em',
// unplugin-icons options
scale: 1,
customCollections: { /* ... */ },
})
```
### iconfont
| Option | Type | Default | Description |
| -------- | ---------------------------------- | --------- | --------------------------------- |
| `prefix` | `string` | `'icon-'` | Class name prefix for icons |
| `assets` | `IconAssetLink \| IconAssetLink[]` | - | iconfont CSS/JS resource URLs |
```ts [.vitepress/config.ts]
icons({
provider: 'iconfont',
default: true,
prefix: 'icon-',
assets: '//at.alicdn.com/w/font_xxx.css',
})
```
### FontAwesome
| Option | Type | Default | Description |
| -------- | ----------------------------------------------------- | --------------- | ---------------------------------------------------- |
| `prefix` | `LiteralUnion<FontAwesomePrefix>` | `'fas'` | Default icon prefix |
| `assets` | `Arrayable<FontAwesomeAssetBuiltIn \| IconAssetLink>` | `'fontawesome'` | Built-in asset name or custom URL |
The `assets` option accepts:
- `'fontawesome'` — Injects the solid, regular, and base kits from the jsDelivr CDN.
- `'fontawesome-with-brands'` — Injects only the brands kit from the jsDelivr CDN.
- A custom `.css` or `.js` URL.
```ts [.vitepress/config.ts]
icons({
provider: 'fontawesome',
default: true,
prefix: 'fas',
assets: 'fontawesome',
})
```
The `prefix` option supports the following aliases:
| Prefix | Alias | Resulting Classes |
| -------- | ------- | --------------------------------------- |
| `fas` | `s` | `fa-solid fa-name` |
| `far` | `r` | `fa-regular fa-name` |
| `fal` | `l` | `fa-light fa-name` |
| `fat` | `t` | `fa-thin fa-name` |
| `fads` | `ds` | `fa-duotone fa-solid fa-name` |
| `fass` | `ss` | `fa-sharp fa-solid fa-name` |
| `fasr` | `sr` | `fa-sharp fa-regular fa-name` |
| `fasl` | `sl` | `fa-sharp fa-light fa-name` |
| `fast` | `st` | `fa-sharp fa-thin fa-name` |
| `fasds` | `sds` | `fa-sharp-duotone fa-solid fa-name` |
| `fab` | `b` | `fa-brands fa-name` |
You can also use the `prefix:name` format in the icon name to specify a prefix for a single icon, e.g. `fab:github`.
### Multiple Providers
```ts [.vitepress/config.ts]
icons([
{ provider: 'iconify' },
{ provider: 'iconfont', default: true, assets: '//at.alicdn.com/w/font_xxx.css' },
{ provider: 'fontawesome', assets: 'fontawesome' },
])
```
With the configuration above, `::name::` uses iconfont by default, while `::iconify name::` and `::fontawesome name::` explicitly select the other providers.# Plugin Overview
The `vitepress-tuck` ecosystem provides a rich set of plugins covering Markdown syntax extensions,
content embedding, code enhancement, and more.
All plugins support two usage modes:
1. **vitepress-tuck mode (recommended)**: One-click integration via the `plugins` option
2. **Native mode**: Manual configuration in VitePress# JSFiddle
<NpmBadge name="vitepress-plugin-jsfiddle" />
Embed [JSFiddle](https://jsfiddle.net/) projects into VitePress pages.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-jsfiddle
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import jsfiddle from 'vitepress-plugin-jsfiddle'
export default defineConfig({
plugins: [jsfiddle()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { jsfiddleMarkdownPlugin } from 'vitepress-plugin-jsfiddle'
export default defineConfig({
markdown: {
config: (md) => {
md.use(jsfiddleMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithJsFiddle } from 'vitepress-plugin-jsfiddle/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithJsFiddle(ctx)
},
} satisfies Theme
```
## Syntax
### Basic Usage
```md
@[jsfiddle](user/id)
```
### With Options
```md
@[jsfiddle title="JS Fiddle" theme="dark" tab="js,css,html,result" height="400px"](pengzhanbo/1xbwz2p9)
```
### Attribute Reference
| Attribute | Type | Default | Description |
| --------- | ------------------ | ---------------------- | ------------------------------------------------- |
| `title` | `string` | `'JS Fiddle'` | Title |
| `theme` | `string` | - | Theme (e.g. `dark`) |
| `tab` | `string` | `'js,css,html,result'` | Tabs to display (comma-separated, spaces removed) |
| `width` | `string` | `'100%'` | Width |
| `height` | `string` | - | Height |
| `ratio` | `number \| string` | - | Aspect ratio |
## Example
```md
@[jsfiddle](pengzhanbo/1xbwz2p9)
```
@[jsfiddle](pengzhanbo/1xbwz2p9)# Mark
<NpmBadge name="vitepress-plugin-mark" />
Mark plugin that adds `==highlight==` syntax support to Markdown,
rendering highlighted text with a scroll-triggered animation and multiple color variants.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-mark
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import mark from 'vitepress-plugin-mark'
export default defineConfig({
plugins: [mark()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { markdownPlugin } from 'vitepress-plugin-mark'
export default defineConfig({
markdown: {
config: (md) => {
md.use(markdownPlugin)
},
},
})
```
Register the component in the theme and import the styles:
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithMark } from 'vitepress-plugin-mark/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithMark(ctx)
},
} satisfies Theme
```
## Syntax
Wrap inline content with `==` to render it as a highlighted `<mark>` element. When the element
scrolls into the viewport, a fill-from-left highlight animation plays once, giving the marked text
a vivid emphasis effect.
```md
==Marked== text
```
**Rendered Result:**
==Marked== text
Inline content inside the markers fully supports Markdown syntax (bold, italic, links, code, etc.):
```md
==**bold**==, ==*italic*==, ==[link](https://example.com)==, ==`code`==
```
**Rendered Result:**
==**bold**==, ==*italic*==, ==[link to](https://example.com)==, ==`code`==
## Color Variants
Specify different highlight colors by appending an [attrs syntax](https://vitepress.dev/guide/markdown#attribute)
to the marker. Variant names correspond to VitePress container types and automatically adapt to dark mode.
```md
==Default==
==note=={.note}
==info=={.info}
==tip=={.tip}
==warning=={.warning}
==caution=={.caution}
==important=={.important}
```
**Rendered Result:**
==Default==
==note=={.note}
==info=={.info}
==tip=={.tip}
==warning=={.warning}
==caution=={.caution}
==important=={.important}
### Variant Reference
| Variant | Description |
| ------------ | --------------------------------- |
| _(default)_ | Yellow highlight |
| `.note` | Cyan highlight |
| `.info` | Neutral gray highlight |
| `.tip` | Green highlight |
| `.warning` | Gold/amber highlight |
| `.caution` | Pink highlight (alias: `.danger`) |
| `.important` | Lavender/purple highlight |
## Customization
Customize the highlight appearance by overriding the following CSS variables in your theme styles:
```css
:root {
--vp-mark-linear-color: #f0a;
}
```
| Variable | Description | Default |
| ------------------------ | --------------------------------------------- | ------------------------------------ |
| `--vp-mark-text` | Text color | `currentcolor` |
| `--vp-mark-bg` | Background color | `transparent` |
| `--vp-mark-linear-color` | Highlight fill color | `#ff0` |
| `--vp-mark-bg-image` | Background image used for the fill (gradient) | `linear-gradient(to right, ...)` |
| `--vp-mark-bg-shift` | Vertical position shift of the background | `0.55lh` |
| `--vp-mark-animation` | Animation shorthand | `mark-highlight 1.25s 0.5s forwards` |
You can also extend highlight color variants by customizing CSS class names:
```css
mark.custom {
--vp-mark-linear-color: #f0a;
}
```
```md
==Custom variant=={.custom}
```
Rendered result:
==Custom variant=={.custom}
<style>
mark.custom {
--vp-mark-linear-color: #f0a;
}
</style># Mermaid
<NpmBadge name="vitepress-plugin-mermaid-tuck" />
Mermaid diagram plugin, supporting Mermaid chart rendering in Markdown.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-mermaid-tuck
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import mermaid from 'vitepress-plugin-mermaid-tuck'
export default defineConfig({
plugins: [
mermaid(),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { mermaidMarkdownPlugin, mermaidVitePlugin } from 'vitepress-plugin-mermaid-tuck'
export default defineConfig({
vite: {
plugins: [mermaidVitePlugin({
options: { theme: 'default' },
})],
},
markdown: {
config: (md) => {
md.use(mermaidMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithMermaid } from 'vitepress-plugin-mermaid-tuck/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithMermaid(ctx)
},
} satisfies Theme
```
## Syntax
Use code blocks with the `mermaid` language tag:
````md
```mermaid
flowchart LR
Start --> Stop
```
````
````md
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice->>John: See you later!
```
````
## Configuration
### MermaidPluginOptions
```ts
interface MermaidPluginOptions {
/**
* Mermaid configuration (excluding startOnLoad and themeVariables)
*/
options?: Omit<MermaidConfig, 'startOnLoad' | 'themeVariables'> & {
themeVariables?: MermaidThemeVariables
}
/**
* Locale configuration
*/
locales?: Record<string, MermaidLocaleData>
}
```
### MermaidThemeVariables
Supports custom theme variables for various Mermaid diagram types, covering:
- Basic variables (background, text color, line color, etc.)
- C4, Class, ER diagram variables
- Flowchart variables
- Gantt chart variables
- Git graph variables
- Journey diagram variables
- Pie chart variables
- Requirement diagram variables
- State diagram variables
- Sequence diagram variables
### MermaidLocaleData
```ts
interface MermaidLocaleData {
chart?: string // Default 'Chart'
source?: string // Default 'Source'
fullscreen?: string // Default 'Fullscreen'
download?: string // Default 'Download'
}
```
## Built-in Languages
The plugin includes built-in support for the following languages:
- English (en, en-US)
- 简体中文 (zh, zh-CN)
- 日本語 (ja)
- 한국어 (ko)
- Español (es)
- Français (fr)
- Русский (ru)
- Deutsch (de)
- Português (pt)
## Examples
```mermaid
---
title: Flowchart
---
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
```
```mermaid
---
title: Sequence Diagram
---
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
Bob-->Alice: Checking with John...
Alice->John: Yes... John, how are you?
```
```mermaid
---
title: Animal Example
---
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
note for Duck "can fly<br>can swim<br>can dive<br>can help in debugging"
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
```
```mermaid
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes weekends
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
```# Npm To
<NpmBadge name="vitepress-plugin-npm-to" />
Automatically converts npm commands to equivalent commands for other package managers (pnpm, yarn, bun, deno).
## Installation
::: npm-to
```sh
npm install vitepress-plugin-npm-to
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import npmTo from 'vitepress-plugin-npm-to'
export default defineConfig({
plugins: [
npmTo(['npm', 'pnpm', 'yarn']),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { npmToPlugin } from 'vitepress-plugin-npm-to'
export default defineConfig({
markdown: {
config: (md) => {
md.use(npmToPlugin, ['npm', 'pnpm', 'yarn'])
},
},
})
```
## Syntax
Use the `::: npm-to` container to wrap npm commands. The plugin automatically converts them into multi-tab code groups:
````md
::: npm-to
```sh
npm install vitepress-plugin-steps
```
:::
````
After rendering, it displays as multiple tabs, each showing the corresponding package manager's install command:
- **npm**: `npm install vitepress-plugin-steps`
- **pnpm**: `pnpm add vitepress-plugin-steps`
- **yarn**: `yarn add vitepress-plugin-steps`
### Supported Command Types
The plugin supports automatic conversion of the following npm commands:
| Command | Example | Support |
| ----------------------- | --------------------- | ----------------------------------------- |
| `npm install` / `npm i` | `npm install react` | Converts to each manager's add command |
| `npm install` (no args) | `npm install` | Converts to pure install command |
| `npm uninstall` | `npm uninstall react` | Converts to each manager's remove command |
| `npm run` | `npm run build` | Converts to each manager's run command |
| `npm create` | `npm create vite` | Converts to each manager's create command |
| `npm init` | `npm init -y` | Converts to each manager's init command |
| `npx` | `npx eslint .` | Converts to each manager's equivalent |
| `npm ci` | `npm ci` | Converts to each manager's ci command |
### Custom Tabs
You can specify which tabs to display using the `tabs` attribute:
````md
::: npm-to tabs="npm,pnpm"
```sh
npm install vitepress-plugin-steps
```
:::
````
## Configuration
```ts
type NpmToPluginOptions =
| NpmToPackageManager[] // e.g. ['npm', 'pnpm', 'yarn']
| {
tabs?: NpmToPackageManager[]
}
type NpmToPackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'deno'
```
- Displays `npm`, `pnpm`, `yarn` tabs by default
- Supports `bun` and `deno` conversion
### Example
````md
::: npm-to
```sh
npm install vitepress-plugin-steps
```
:::
````
::: npm-to
```sh
npm install vitepress-plugin-steps
```
:::# Obsidian
<NpmBadge name="vitepress-plugin-obsidian" />
Provides Obsidian-style Markdown syntax support, including Wiki links, Callout annotations, embedded files, and comment syntax.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-obsidian
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import obsidian from 'vitepress-plugin-obsidian'
export default defineConfig({
plugins: [
obsidian({
// All optional, default to true
callout: true,
comment: true,
embedLink: true,
wikiLink: true,
}),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { obsidianMarkdownPlugin } from 'vitepress-plugin-obsidian'
export default defineConfig({
markdown: {
config: (md) => {
md.use(obsidianMarkdownPlugin, {
callout: true,
comment: true,
embedLink: true,
wikiLink: true,
})
},
},
})
```
## Wiki Links
Wiki links are Obsidian's syntax for linking to other notes. Use double brackets `[[ ]]` to create internal links.
### Syntax
```md
[[filename]]
[[filename#heading]]
[[filename#heading#subheading]]
[[filename|alias]]
[[filename#heading|alias]]
[[https://example.com|external link]]
```
### File Name Search Rules
When using Wiki links, file names are matched according to the following search rules:
**Matching Priority:**
1. **Full Path** — exact match of the file path
2. **Fuzzy Match** — match by filename at the end of the path, preferring the shortest path
**Path Resolution Rules:**
- **Relative paths** (starting with `.`): resolved relative to the current file's directory
- **Absolute paths** (not starting with `.`): searched across the entire document tree, preferring the shortest match
- **Directory form** (ending with `/`): matches the `index.md` in that directory
**Example:**
Given the following document structure:
```txt
docs/
├── index.md
├── guide/
│ ├── index.md
│ └── markdown/
│ └── obsidian.md
```
In `docs/guide/markdown/obsidian.md`:
| Syntax | Match Result |
| -------------- | --------------------------------------------------------------- |
| `[[obsidian]]` | matches `docs/guide/markdown/obsidian.md` (via filename search) |
| `[[./]]` | matches `docs/guide/markdown/index.md` (relative path) |
| `[[../]]` | matches `docs/guide/README.md` (parent directory) |
| `[[guide/]]` | matches `docs/guide/README.md` (directory form) |
### Examples
**External Link:**
**Input:**
```md
[[https://example.com|external link]]
```
**Output:**
[[https://example.com|external link]]
**Internal Anchor Links:**
**Input:**
```md
[[npm-to]] <!-- via filename search -->
[[#Wiki Links]] <!-- current page heading -->
[[file-tree#Configuration]] <!-- via filename search, link to heading -->
```
**Output:**
[[npm-to]]
[[#Wiki Links]]
[[file-tree#Configuration]]
[Obsidian Official - **Wiki Links**](https://help.obsidian.md/links){.readmore}
## Embedded Content
Embed syntax allows you to insert content from other files into the current page.
### Syntax
```md
![[filename]]
![[filename#heading]]
![[filename#heading#subheading]]
```
File name search rules are the same as [Wiki Links](#file-name-search-rules).
::: info Paths starting with `/` or without a `./` prefix load resources from the `public` directory
:::
### Image Embedding
**Syntax:**
```md
![[image]]
![[image|width]]
![[image|widthxheight]]
```
Supported formats: `jpg`, `jpeg`, `png`, `gif`, `avif`, `webp`, `svg`, `bmp`, `ico`, `tiff`, `apng`, `jfif`, `pjpeg`, `pjp`, `xbm`
**Example:**
```md
![[tuck-logo.svg]]
```
![[tuck-logo.svg|125]]
### PDF Embedding
> [!NOTE]
> PDF embedding requires the [vitepress-plugin-pdf](./pdf.md) plugin to work properly.
**Syntax:**
```md
![[document.pdf]]
![[document.pdf#page=1]] <!-- #page=1 for first page -->
![[document.pdf#page=1#height=300]] <!-- #page=page #height=height -->
```
Supported formats: `pdf`
**Example:**
```md
![[https://plume.pengzhanbo.cn/files/sample-1.pdf]]
```
![[https://plume.pengzhanbo.cn/files/sample-1.pdf]]
---
### Audio Embedding
**Syntax:**
```md
![[audio file]]
```
Supported formats: `mp3`, `flac`, `wav`, `ogg`, `opus`, `webm`, `acc`
---
### Video Embedding
> [!NOTE]
> Video embedding requires the [vitepress-plugin-video](./video.md) plugin to work properly.
**Syntax:**
```md
![[video file]]
![[video file#height=400]] <!-- Set video height -->
```
Supported formats: `mp4`, `webm`, `mov`, etc.
---
### Content Fragment Embedding
Use `#heading` to embed content fragments under specific headings:
**Input:**
```md
![[my-note]]
![[my-note#heading-one]]
![[my-note#heading-one#subheading]]
```
[Obsidian Official - Embed Files](https://help.obsidian.md/embeds){.readmore}
[Obsidian Official - File Formats](https://help.obsidian.md/file-formats){.readmore}
## Callout
Callout is a syntax for highlighting important information, similar to VitePress's `::: note` alert syntax.
### Syntax
```md
> [!note]
> Content
```
**Optional Title:**
```md
> [!tip] Custom Title
> Content
```
### Types
Callout supports the following types, with aliases automatically mapping to the corresponding main type:
| Type | Aliases | Description |
| ----------- | ------------------------------------------------------------------- | -------------------------- |
| `note` | `quote`, `cite` | Notes, quotes |
| `tip` | `hint`, `check`, `done`, `success` | Tips, hints |
| `info` | `todo` | Info, todos |
| `warning` | `question`, `help`, `faq` | Warnings, questions, help |
| `caution` | `attention`, `failure`, `fail`, `missing`, `danger`, `error`, `bug` | Cautions, failures, danger |
| `important` | `example` | Important, examples |
| `details` | `abstract`, `summary`, `tldr` | Details, summaries |
### Examples
**Basic Usage:**
**Input:**
```md
> [!NOTE]
> This is a note callout.
```
**Output:**
> [!NOTE]
> This is a note callout.
---
**With Title:**
**Input:**
```md
> [!TIP] Useful Tip
> Using `pnpm` can significantly speed up dependency installation.
```
**Output:**
> [!TIP] Useful Tip
> Using `pnpm` can significantly speed up dependency installation.
---
**Multiple Types:**
**Input:**
```md
> [!success]
> Operation completed successfully!
>
> [!warning]
> This is a warning message.
>
> [!caution]
> Proceed with caution, this operation is irreversible.
```
**Output:**
> [!success]
> Operation completed successfully!
> [!warning]
> This is a warning message.
> [!caution]
> Proceed with caution, this operation is irreversible.
---
**Details Type:**
The `details` type renders as an HTML `<details>` element, supporting expand/collapse:
**Input:**
```md
> [!details]
> Click to expand more content
>
> This is hidden content.
```
**Output:**
> [!details]
> Click to expand more content
>
> This is hidden content.
[Obsidian Official - Callouts](https://help.obsidian.md/callouts){.readmore}
## Comments
Content wrapped with `%%` is treated as a comment and will not be rendered on the page.
### Syntax
**Inline Comments:**
```md
This is an %%inline comment%% example.
```
**Block Comments:**
```md
%%
This is a block comment.
It can span multiple lines.
%%
```
### Examples
**Inline Comment:**
**Input:**
```md
This is an %%inline comment%% example.
```
**Output:**
This is an %%inline comment%% example.
---
**Block Comment:**
**Input:**
```md
Content before the comment
%%
This is a block comment.
It can span multiple lines.
%%
Content after the comment
```
**Output:**
Content before the comment
%%
This is a block comment.
%%
It can span multiple lines.
[Obsidian Official - Comments](https://help.obsidian.md/syntax#comments){.readmore}
## Notes
- These plugins provide **compatibility support**, not a full implementation of all Obsidian features
- Some Obsidian-specific features (such as graph view for internal links, backlinks, etc.) are not supported
- When embedding content, the embedded page also participates in the theme's build process
- PDF embedding requires the [vitepress-plugin-pdf](./pdf.md) plugin to work properly
- Video embedding requires the [vitepress-plugin-video](./video.md) plugin to work properly
- Embedded resources starting with `/` or using `./` form will be loaded from the `public` directory# PDF
<NpmBadge name="vitepress-plugin-pdf" />
PDF file embedding plugin for displaying a PDF viewer in the page.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-pdf
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import pdf from 'vitepress-plugin-pdf'
export default defineConfig({
plugins: [pdf()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { pdfMarkdownPlugin } from 'vitepress-plugin-pdf'
export default defineConfig({
markdown: {
config: (md) => {
md.use(pdfMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithPDF } from 'vitepress-plugin-pdf/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithPDF(ctx)
},
} satisfies Theme
```
## Syntax
Embed a PDF using `@[pdf]()`:
```md
@[pdf](https://example.com/sample.pdf)
@[pdf](./sample.pdf)
```
### Specifying a Page
```md
@[pdf page="3"](https://example.com/sample.pdf)
@[pdf p="3"](https://example.com/sample.pdf)
```
### Configuration Options
```md
@[pdf no-toolbar width="100%" height="600px" zoom="100"](https://example.com/sample.pdf)
```
### Attribute Reference
| Attribute | Type | Default | Description |
| ------------ | ------------------ | -------- | ------------ |
| `width` | `string` | `'100%'` | Width |
| `height` | `string` | - | Height |
| `ratio` | `number \| string` | - | Aspect ratio |
| `zoom` | `number` | `50` | Zoom level |
| `no-toolbar` | `boolean` | `false` | Hide toolbar |
## Example
```md
@[pdf](https://plume.pengzhanbo.cn/files/sample-1.pdf)
```
@[pdf](https://plume.pengzhanbo.cn/files/sample-1.pdf)# PlantUML
<NpmBadge name="vitepress-plugin-plantuml" />
PlantUML diagram plugin, supporting PlantUML chart rendering in Markdown.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-plantuml
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import plantuml from 'vitepress-plugin-plantuml'
export default defineConfig({
plugins: [
plantuml(),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { plantumlMarkdownPlugin, plantumlVitePlugin } from 'vitepress-plugin-plantuml'
export default defineConfig({
vite: {
plugins: [plantumlVitePlugin()],
},
markdown: {
config: (md) => {
md.use(plantumlMarkdownPlugin)
},
languageAlias: { plantuml: 'txt' },
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithPlantuml } from 'vitepress-plugin-plantuml/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithPlantuml(ctx)
},
} satisfies Theme
```
## Syntax
Use code blocks with the `plantuml` language tag:
````md
```plantuml
@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
@enduml
```
````
### Output Format
The plugin supports `svg` (default) and `png` output formats. You can specify the format per diagram:
````md
```plantuml png
@startuml
class Example {
+attribute: string
+method(): void
}
@enduml
```
````
Or set a global default:
```ts
plantuml({ format: 'png' }) // default is 'svg'
```
## Configuration
### PlantumlPluginOptions
```ts
interface PlantumlPluginOptions {
/**
* Output format, 'svg' | 'png'
* @default 'svg'
*/
format?: PlantumlFormat
/**
* PlantUML server URL
* @default 'https://www.plantuml.com/plantuml'
*/
serverURL?: string
}
```
## Features
- **Dark / Light mode** — Automatically generates both dark and light diagram variants, following the VitePress theme
- **Chart / Source tabs** — Toggle between the rendered diagram and its PlantUML source code
- **Fullscreen mode** — Click the fullscreen button to view the diagram in an overlay
- **Download** — Download the current diagram as an image file
- **Multi-language** — Built-in support for English, Chinese, Japanese, Korean, Spanish, French, Russian, German, and Portuguese
- **SVG optimization** — SVGs are automatically optimized via SVGO, removing redundant styles and background layers
- **Build caching** — Rendered diagrams are cached to disk for faster incremental builds
## Built-in Languages
The plugin includes built-in support for the following languages:
- English (en, en-US)
- 简体中文 (zh, zh-CN)
- 日本語 (ja)
- 한국어 (ko)
- Español (es)
- Français (fr)
- Русский (ru)
- Deutsch (de)
- Português (pt)
## Examples
### Sequence Diagram
```plantuml
@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
Alice -> Bob: Another authentication Request
Alice <-- Bob: Another authentication Response
@enduml
```
### Use Case Diagram
```plantuml
@startuml
left to right direction
actor "Customer" as customer
actor "Cashier" as cashier
rectangle "POS System" {
customer -- (Checkout)
(Checkout) -- cashier
(Checkout) .> (Print Receipt) : include
(Checkout) .> (Payment) : include
(Payment) .> (Cash Payment)
(Payment) .> (Scan to Pay)
}
@enduml
```
### Class Diagram
```plantuml
@startuml
class Vehicle
class Car
class Bike
Vehicle <|-- Car
Vehicle <|-- Bike
class Engine
class Wheel
Car *-- Engine
Car *-- Wheel
@enduml
```
### Activity Diagram
```plantuml
@startuml
start
:User Login;
if (Authenticated?) then (yes)
:Enter Dashboard;
if (New Messages?) then (yes)
:Show Notification;
else (no)
:Continue Browsing;
endif
else (no)
:Show Error;
:Return to Login;
endif
stop
@enduml
```# Plot
<NpmBadge name="vitepress-plugin-plot" />
Hidden text plugin that reveals concealed text content on click or hover.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-plot
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import plot from 'vitepress-plugin-plot'
export default defineConfig({
plugins: [
plot({
trigger: 'hover', // 'hover' | 'click', default 'hover'
effect: 'mask', // 'mask' | 'blur', default 'mask'
}),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { plotMarkdownPlugin } from 'vitepress-plugin-plot'
export default defineConfig({
markdown: {
config: (md) => {
md.use(plotMarkdownPlugin, {
trigger: 'hover',
effect: 'mask',
})
},
},
})
```
```ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import { enhanceAppWithPlot } from 'vitepress-plugin-plot/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithPlot(ctx)
},
} satisfies Theme
```
## Syntax
Wrap hidden text with `!!`:
```md
The answer is !!plot!!
```
Use `classname` to set interaction behavior:
```md
!!plot!!{.click .blur}
```
Supported `classname` values:
- `.click` / `.hover`: Reveal on click / Reveal on hover
- `.blur` / `.mask`: Blur effect / Mask effect
## Configuration
```ts
interface PlotOptions {
/**
* Trigger method
* - 'hover': Reveal on hover
* - 'click': Reveal on click
* @default 'hover'
*/
trigger?: 'hover' | 'click'
/**
* Hide effect
* - 'mask': Mask effect (default)
* - 'blur': Blur effect
* @default 'mask'
*/
effect?: 'mask' | 'blur'
}
```
## Examples
```md
Lu Xun once said: "!!I never said that!!"
```
Lu Xun once said: "!!I never said that!!"
```md
There is no royal road to learning, !!but hard work pays off!!{.click .blur}.
```
There is no royal road to learning, !!but hard work pays off!!{.click .blur}.# QRCode
<NpmBadge name="vitepress-plugin-qrcode" />
QR code generation plugin, generating QR codes from text or links.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-qrcode
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import qrcode from 'vitepress-plugin-qrcode'
export default defineConfig({
plugins: [qrcode()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { qrcodeMarkdownPlugin } from 'vitepress-plugin-qrcode'
export default defineConfig({
markdown: {
config: (md) => {
md.use(qrcodeMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithQrcode } from 'vitepress-plugin-qrcode/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithQrcode(ctx)
},
} satisfies Theme
```
## Syntax
### Embed Block Syntax
```md
@[qrcode](https://www.baidu.com)
@[qrcode](arbitrary text)
@[qrcode](./caniuse.md)
```
### Styled Card Mode
```md
@[qrcode card title="Scan to visit"](https://www.baidu.com)
```
### Container Syntax
Suitable for long text:
```md
::: qrcode title="Scan to visit"
https://www.baidu.com
:::
```
### Attribute Reference
| Attribute | Type | Description |
| ---------- | --------- | -------------------------------------- |
| `card` | `boolean` | Display in card mode |
| `title` | `string` | Card title |
| `logo` | `string` | QR code logo, link format, optional |
| `logoSize` | `number` | Logo size ratio, optional, default 0.2 |
| `width` | `number` | QR code width, optional |
## Examples
```md
@[qrcode](https://www.baidu.com)
```
@[qrcode](https://www.baidu.com)
**Internal links auto-add logo:**
```md
@[qrcode](./file-tree.md)
```
@[qrcode](./file-tree.md)
**Using card mode:**
```md
@[qrcode card title="Scan to visit File Tree Plugin"](./file-tree.md)
```
@[qrcode card title="Scan to visit File Tree Plugin"](./file-tree.md)# Repo Card
<NpmBadge name="vitepress-plugin-repo-card" />
A repository information card plugin that displays detailed GitHub/Gitee repository
cards in your Markdown. Supports embed syntax for individual cards and container
syntax for multi-card grid layouts.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-repo-card
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import repoCard from 'vitepress-plugin-repo-card'
export default defineConfig({
plugins: [repoCard()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { repoCardMarkdownPlugin } from 'vitepress-plugin-repo-card'
export default defineConfig({
markdown: {
config: (md) => {
md.use(repoCardMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithRepoCard } from 'vitepress-plugin-repo-card/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithRepoCard(ctx)
},
} satisfies Theme
```
## Syntax
### Embed Syntax
Use the `@[repo]()` syntax to embed individual repository cards. Defaults to GitHub
if `register` is omitted.
```md
@[repo](owner/name)
@[repo github](owner/name)
@[repo gitee](owner/name)
```
### Display Full Name
Use the `fullname` parameter to show the `owner/name` full path. For
organization-owned repositories, the full name is displayed automatically.
```md
@[repo fullname github](pengzhanbo/vitepress-tuck)
```
### Container Syntax
Use the `::: repo` container to display multiple repository cards in a responsive
grid layout.
```md
::: repo
@[repo github](vuejs/vitepress)
@[repo github](vuejs/core)
:::
```
## Examples
### Single Repository Card
**GitHub repository:**
```md
@[repo github](vuejs/vitepress)
```
@[repo github](vuejs/vitepress)
**Gitee repository:**
```md
@[repo gitee](openharmony/kernel_liteos_a)
```
@[repo gitee](openharmony/kernel_liteos_a)
**Display full name:**
```md
@[repo fullname](pengzhanbo/vitepress-tuck)
```
@[repo fullname](pengzhanbo/vitepress-tuck)
### Multi-Card Grid Layout
```md
::: repo
@[repo fullname](pengzhanbo/vitepress-tuck)
@[repo](pengzhanbo/vite-plugin-mock-dev-server)
@[repo](pengzhanbo/utils)
@[repo](pengzhanbo/vuepress-theme-plume)
:::
```
::: repo
@[repo fullname](pengzhanbo/vitepress-tuck)
@[repo](pengzhanbo/vite-plugin-mock-dev-server)
@[repo](pengzhanbo/utils)
@[repo](pengzhanbo/vuepress-theme-plume)
:::
## Card Information
Each repository card displays the following:
| Field | Description |
| ----------- | ------------------------------------ |
| Name | Repository name or `owner/name` full |
| Visibility | Public / Private badge |
| Archived | Warning badge if archived |
| Description | Repository description text |
| Language | Primary language with color dot |
| Stars | Formatted count (e.g. `1.2k`) |
| Forks | Formatted count (e.g. `1.2k`) |
| License | License name (if available) |
## Component Usage
You can also use the `VPRepoCard` component directly:
```vue
<script setup lang="ts">
import { VPRepoCard } from 'vitepress-plugin-repo-card/client'
</script>
<template>
<VPRepoCard repo="vuejs/vitepress" register="github" />
<VPRepoCard repo="owner/name" register="gitee" fullname />
</template>
```
### Props
| Prop | Type | Default | Description |
| ---------- | --------------------- | ---------- | --------------------------------- |
| `repo` | `string` | (required) | Repository in `owner/name` format |
| `register` | `'github' \| 'gitee'` | `'github'` | Repository platform |
| `fullname` | `boolean` | - | Display full name (`owner/name`) |# StackBlitz
<NpmBadge name="vitepress-plugin-stackblitz" />
Embed [StackBlitz](https://stackblitz.com/) projects into VitePress pages.
Supports embedding online editors via StackBlitz ID, GitHub repository, or local project files.
Can also display as a button to open in a new tab.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-stackblitz
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import stackblitz from 'vitepress-plugin-stackblitz'
export default defineConfig({
plugins: [stackblitz()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { stackblitzMarkdownPlugin } from 'vitepress-plugin-stackblitz'
export default defineConfig({
markdown: {
config: (md) => {
md.use(stackblitzMarkdownPlugin)
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithStackBlitz } from 'vitepress-plugin-stackblitz/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithStackBlitz(ctx)
},
} satisfies Theme
```
## Syntax
The plugin provides two syntaxes for embedding StackBlitz projects:
embed syntax for referencing external projects, and container syntax for writing project
files directly inline within Markdown.
### Embed by StackBlitz ID
```md
@[stackblitz](sdk-github-project)
```
### Embed by GitHub Repository
```md
@[stackblitz github](user/repo)
```
### Embed Local Project
Place a `stackblitz.config.json` (or `.yaml`, `.yml`) configuration file in your project directory, then use the `local` attribute:
```md
@[stackblitz local](path/to/your/project)
```
`path` supports the following prefixes:
| Prefix | Description |
| ------ | ------------------------------------------------- |
| `@` | Relative to VitePress `srcDir` |
| `/` | Relative to VitePress project root |
| - | Relative to the current markdown file's directory |
See [Local Project Configuration](#local-project-configuration) for more details.
### Button Mode
Display as a button that opens the project in a new tab:
```md
@[stackblitz button](stackblitz-id)
```
It can also be combined with GitHub:
```md
@[stackblitz github button](user/repo)
```
### Container Syntax
Write project files directly inline within Markdown, ideal for quickly demonstrating simple projects:
````md
::: stackblitz title="Project" description="Project description" template="javascript"
```yml [config]
title: Project
template: javascript
description: Project description
```
```json [package.json]
{
"name": "project",
"version": "1.0.0"
}
```
```js [index.js]
console.log('Hello StackBlitz!');
```
```html [index.html]
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Hello StackBlitz!</h1>
<script src="./index.js"></script>
</body>
</html>
```
:::
````
### Attribute Reference
#### Embed / Open Options
Applicable to both embed syntax and button mode:
| Attribute | Type | Default | Description |
| ------------------ | ------------------------------------ | ----------- | --------------------------------------------- |
| `theme` | `'dark' \| 'light' \| 'default'` | auto | Color theme, auto follows VitePress dark mode |
| `view` | `'default' \| 'preview' \| 'editor'` | `'default'` | Initial UI view |
| `height` | `number` | `400` | Embed height (embed mode only) |
| `width` | `number` | - | Embed width (embed mode only) |
| `clickToLoad` | `boolean` | `false` | Show "click to run" dialog |
| `openFile` | `string \| string[]` | - | File(s) to open on load |
| `hideExplorer` | `boolean` | `false` | Hide the file explorer |
| `hideDevTools` | `boolean` | `false` | Hide the dev tools console |
| `showSidebar` | `boolean` | `false` | Show sidebar as open on load |
| `terminalHeight` | `number` (0-100) | - | Terminal height percentage |
| `devToolsHeight` | `number` (0-100) | - | Dev tools height percentage |
| `newWindow` | `boolean` | `false` | Open project in a new tab |
| `forceEmbedLayout` | `boolean` | `false` | Force embed layout (deprecated) |
| `origin` | `string` | - | StackBlitz EE instance URL |
#### Project Options
Only applicable to local project embed mode and container syntax:
| Attribute | Type | Default | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------ |
| `title` | `string` | - | Project title (required) |
| `description` | `string` | - | Project description (required) |
| `template` | `'angular-cli' \| 'create-react-app' \| 'html' \| 'javascript' \| 'typescript' \| 'polymer' \| 'vue' \| 'node'` | - | Project template (required) |
| `dependencies` | `Record<string, string>` | - | npm dependencies |
| `files` | `Record<string, string>` | - | Project files (auto-loaded for local mode) |
#### Build Settings
Set via `settings`-prefixed attributes, only applicable to local project embed mode and container syntax:
| Attribute | Type | Default | Description |
| ---------------------- | --------------------------------- | -------- | ------------------------------- |
| `settingsTrigger` | `'auto' \| 'save' \| 'keystroke'` | `'auto'` | Compilation trigger timing |
| `settingsAction` | `'hmr' \| 'refresh'` | `'hmr'` | How to inject compiled changes |
| `settingsClearConsole` | `boolean` | `true` | Clear console after compilation |
```md
@[stackblitz local title="Demo" description="A demo" template="html" settingsTrigger="save" settingsAction="refresh"](path/to/project)
```
## Local Project Configuration
When using `@[stackblitz local](path)` to embed a local project, the plugin automatically:
1. Loads all files from the specified directory (excluding `node_modules`)
2. Searches for `stackblitz.config.json`, `stackblitz.config.yaml`, `stackblitz.config.yml` in order
3. Merges the configuration file options with the loaded files
Example `stackblitz.config.json`:
```json
{
"$schema": "../../node_modules/vitepress-plugin-stackblitz/schema.json",
"title": "Project",
"description": "Project description",
"template": "javascript",
"dependencies": {
"lodash": "^4.17.0"
},
"settings": {
"trigger": "save"
}
}
```
> [!TIP]
> Including the `$schema` field provides intelligent autocompletion and validation for configuration files in your editor.
>
> ```json
> {
> "$schema": "https://unpkg.com/vitepress-plugin-stackblitz/schema.json"
> }
> ```
## Example
### StackBlitz ID Embed
```md
@[stackblitz](sdk-github-project)
```
@[stackblitz](sdk-github-project)
### Button Mode
```md
@[stackblitz button](sdk-github-project)
```
@[stackblitz button](sdk-github-project)
### Container Syntax
````md
::: stackblitz button
```yml [config]
title: Project
template: javascript
description: Project description
```
```json [package.json]
{
"name": "project",
"version": "1.0.0",
"description": "Project description",
"main": "index.js",
"keywords": ["project"],
"author": "Project Author",
"license": "MIT"
}
```
```js [index.js]
console.log('Hello StackBlitz!');
```
```html [index.html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project</title>
</head>
<body>
<h1>Hello StackBlitz!</h1>
<script src="./index.js"></script>
</body>
</html>
```
:::
````
::: stackblitz button
```yml [config]
title: Project
template: javascript
description: Project description
```
```json [package.json]
{
"name": "project",
"version": "1.0.0",
"description": "Project description",
"main": "index.js",
"keywords": ["project"],
"author": "Project Author",
"license": "MIT"
}
```
```js [index.js]
console.log('Hello StackBlitz!');
```
```html [index.html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project</title>
</head>
<body>
<h1>Hello StackBlitz!</h1>
<script src="./index.js"></script>
</body>
</html>
```
:::
### Local Project Embed
@[code-tree title="Local Project Directory" entry="stackblitz.config.json"](@/snippets/stack)
```md
@[stackblitz local](@/snippets/stack)
```
@[stackblitz local](@/snippets/stack)# Steps
<NpmBadge name="vitepress-plugin-steps" />
Step container plugin for creating step-by-step guided content in Markdown.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-steps
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import steps from 'vitepress-plugin-steps'
export default defineConfig({
plugins: [steps()],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { stepsMarkdownPlugin } from 'vitepress-plugin-steps'
export default defineConfig({
markdown: {
config: (md) => {
md.use(stepsMarkdownPlugin)
},
},
})
```
Also import the styles in the theme:
```ts [.vitepress/theme/index.ts]
import 'vitepress-plugin-steps/style.css'
```
## Syntax
Use the `::: steps` container to wrap step content, with each step starting from an unordered/ordered list item:
```md
::: steps
- Step One
Description for step one
- Step Two
Description for step two
- Step Three
Description for step three, supports heading syntax
:::
```
**Rendered Result:**
::: steps
- Step One
Description for step one
- Step Two
Description for step two
- Step Three
Description for step three, supports heading syntax
:::# Video
<NpmBadge name="vitepress-plugin-video" />
Multi-platform video embedding plugin, supporting Bilibili, YouTube, AcFun, and ArtPlayer.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-video
```
:::
## Usage
### vitepress-tuck Mode <Badge type="tip">Recommended</Badge>
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress-tuck'
import video from 'vitepress-plugin-video'
export default defineConfig({
plugins: [
video({
// All optional, default to true
artplayer: true,
youtube: true,
bilibili: true,
acfun: true,
}),
],
})
```
[Learn more about **vitepress-tuck**](../guide/quick-start.md){.readmore}
### Native Mode
```ts [.vitepress/config.ts]
import { defineConfig } from 'vitepress'
import { videoMarkdownPlugin } from 'vitepress-plugin-video'
export default defineConfig({
markdown: {
config: (md) => {
md.use(videoMarkdownPlugin, {
artplayer: true,
youtube: true,
bilibili: true,
acfun: true,
})
},
},
})
```
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import { enhanceAppWithVideo } from 'vitepress-plugin-video/client'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp(ctx) {
enhanceAppWithVideo(ctx)
},
} satisfies Theme
```
## Syntax
### Bilibili
Embed Bilibili videos:
```md
@[bilibili](bvid)
@[bilibili](aid cid)
@[bilibili p2 autoplay time=30](bvid)
```
| Option | Type | Description |
| ----------- | ------------------ | -------------------------------------- |
| `p{number}` | - | Video part number |
| `autoplay` | `boolean` | Auto play |
| `time` | `number \| string` | Start time, seconds or HH:MM:SS format |
### YouTube
Embed YouTube videos:
```md
@[youtube](video_id)
@[youtube autoplay loop start=10 end=120](video_id)
```
| Option | Type | Description |
| ---------- | --------- | --------------------- |
| `autoplay` | `boolean` | Auto play |
| `loop` | `boolean` | Loop playback |
| `start` | `number` | Start time in seconds |
| `end` | `number` | End time in seconds |
### AcFun
Embed AcFun videos:
```md
@[acfun](ac_id)
```
### ArtPlayer
Use ArtPlayer to embed local or remote videos:
```md
@[artPlayer](/videos/demo.mp4)
@[artPlayer muted autoplay poster="/cover.jpg" width="800px"](/videos/demo.mp4)
```
| Option | Type | Default | Description |
| ---------- | --------- | -------- | ------------------------- |
| `autoplay` | `boolean` | `false` | Auto play |
| `muted` | `boolean` | `false` | Muted |
| `loop` | `boolean` | `false` | Loop playback |
| `volume` | `number` | `0.75` | Volume level |
| `poster` | `string` | - | Cover image URL |
| `autoMini` | `boolean` | `false` | Auto mini mode |
| `width` | `string` | `"100%"` | Player width |
| `height` | `string` | - | Player height |
| `ratio` | `string` | - | Aspect ratio, e.g. "16:9" |
Supports `mp4`, `mp3`, `webm`, `ogg`, `mkv`, `mov` formats.
If your video is in `mpd` or `dash` format, you'll also need to install `dashjs`:
:::npm-to
```sh
npm i dashjs
```
:::
If your video is in `m3u8` or `hls` format, you'll also need to install `hls.js`:
:::npm-to
```sh
npm i hls.js
```
:::
If your video is in `ts` or `flv` format, you'll also need to install `mpegts.js`:
:::npm-to
```sh
npm i mpegts.js
```
:::
## Configuration
```ts
interface VideoPluginOptions {
/**
* Enable ArtPlayer
* @default true
*/
artplayer?: boolean
/**
* Enable YouTube video embedding
* @default true
*/
youtube?: boolean
/**
* Enable Bilibili video embedding
* @default true
*/
bilibili?: boolean
/**
* Enable AcFun video embedding
* @default true
*/
acfun?: boolean
}
```
## Examples
### Bilibili
```md
@[bilibili](BV1EZ42187Hg)
```
@[bilibili](BV1EZ42187Hg)
### YouTube
```md
@[youtube](0JJPfz5dg20)
```
@[youtube](0JJPfz5dg20)
### AcFun
```md
@[acfun](ac47431669)
```
@[acfun](ac47431669)
### ArtPlayer
```md
@[artPlayer](https://artplayer.org/assets/sample/video.mp4)
```
@[artPlayer](https://artplayer.org/assets/sample/video.mp4)---
watermark: true
---
# Watermark
<NpmBadge name="vitepress-plugin-watermark" />
Add watermark to your site. Pure client-side implementation, no node-side configuration required.
## Installation
::: npm-to
```sh
npm install vitepress-plugin-watermark
```
:::
## Usage
This plugin only provides a client-side `setupWatermark` function, which must be called inside the
`<script setup>` block of a Layout wrapper component.
Create a custom Layout wrapper component:
```vue [.vitepress/theme/Layout.vue]
<script setup lang="ts">
import { setupWatermark } from 'vitepress-plugin-watermark'
import Theme from 'vitepress/theme'
import { h, useAttrs, useSlots } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
const Layout = () => h(Theme.Layout, attrs, slots)
setupWatermark()
</script>
<template>
<Layout />
</template>
```
Then register this Layout in your theme:
```ts [.vitepress/theme/index.ts]
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import Layout from './Layout.vue'
export default {
extends: DefaultTheme,
Layout,
} satisfies Theme
```
## Configuration
`setupWatermark` accepts an optional configuration object:
```ts
setupWatermark({
enabled: true,
content: 'My Watermark',
fontColor: '#76747f',
globalAlpha: 0.165,
width: 200,
height: 200,
rotate: -22,
fontSize: '16px',
fontFamily: 'sans-serif',
})
```
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `enabled` | `boolean \| ((pageData: PageData) => boolean)` | `true` | Enable watermark; supports a function for dynamic control |
| `content` | `string` | Site title | Watermark text content |
| `fontColor` | `string` | `'#76747f'` | Font color |
| `globalAlpha` | `number` | `0.165` (normal) / `0.005` (blind mode) | Opacity |
| `mode` | `'default' \| 'blind'` | `'default'` | Watermark mode: `'blind'` for blind watermark |
| `width` | `number` | — | Width of each watermark cell |
| `height` | `number` | — | Height of each watermark cell |
| `rotate` | `number` | — | Rotation angle in degrees |
| `fontSize` | `string` | — | Font size |
| `fontFamily` | `string` | — | Font family |
| `fontStyle` | `string` | — | Font style |
| `fontWeight` | `string` | — | Font weight |
| `image` | `string` | — | Image watermark URL |
| `layout` | `'default' \| 'grid'` | — | Layout mode |
| `zIndex` | `number` | — | CSS z-index |
| `mutationObserve` | `boolean` | — | Enable DOM mutation observer protection |
| `monitorProtection` | `boolean` | — | Enable monitoring protection |
| `movable` | `boolean` | — | Allow dragging the watermark |
| `parent` | `Element \| string` | — | Mount target element |
For more options, see the [watermark-js-plus](https://github.com/zhensherlock/watermark-js-plus) documentation.
## Per-Page Watermark
Control watermark on individual pages via frontmatter:
### Enable Watermark
```yaml
---
watermark: true
---
```
### Custom Text
```yaml
---
watermark: CONFIDENTIAL
---
```
### Full Customization
```yaml
---
watermark:
content: DRAFT
fontColor: '#ff0000'
globalAlpha: 0.3
rotate: 30
---
```
### Disable on Specific Pages
```yaml
---
watermark: false
---
```
### Dynamic Enable via Function
Use an `enabled` function to dynamically control watermark based on the page path:
```ts
setupWatermark({
enabled: (pageData) => {
// Only enable on pages under guide/
return pageData.relativePath.startsWith('guide/')
},
})
```---
layout: home
title: VitePress Tuck
hero:
name: VitePress Tuck
text: Enhance vitepress configuration, provide plugins capability.
actions:
- text: Get Started
link: /guide/quick-start
- text: Github
link: https://github.com/pengzhanbo/vitepress-tuck
theme: alt
image:
src: /tuck-logo.svg
alt: VitePress Tuck
---