Components
Overview
VitePress allows you to use Vue components directly in your Markdown files, creating interactive and dynamic documentation. This guide covers how to use components in VitePress, from basic usage to advanced techniques.
Using Components in Markdown
Basic Usage
You can use Vue components directly in your Markdown files:
# My Page
This is a regular paragraph.
<MyComponent />
More Markdown content...
Passing Props
Pass props to components just like in Vue templates:
<MyComponent
title="Hello World"
:count="5"
@click="handleClick"
/>
Using Slots
Components can receive content through slots:
<CustomContainer>
This content will be passed as the default slot.
- You can use **Markdown** inside slots
- Lists work too
</CustomContainer>
Named slots are also supported:
<CustomLayout>
<template #header>
# This is the header
</template>
Main content goes here.
<template #footer>
*Footer content with Markdown*
</template>
</CustomLayout>
Creating Components
Local Components
Create components in your VitePress theme directory:
.vitepress/
theme/
components/
MyComponent.vue
<!-- .vitepress/theme/components/MyComponent.vue -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<div class="my-component">
<p>Current count: {{ count }}</p>
<button @click="count++">Increment</button>
</div>
</template>
<style scoped>
.my-component {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
Registering Components
Register your components in the theme's index.js
file:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyComponent from './components/MyComponent.vue'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.component('MyComponent', MyComponent)
}
}
Using Script Setup in Markdown
You can use <script setup>
directly in Markdown files:
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
# Interactive Component
Current count: {{ count }}
<button @click="increment">Increment</button>
Built-in Components
VitePress provides several built-in components:
Badge
Add status badges to your text:
<Badge type="info" text="default" />
<Badge type="tip" text="recommended" />
<Badge type="warning" text="caution" />
<Badge type="danger" text="deprecated" />
Code
Enhanced code blocks with titles and highlighting:
<Code lang="js" title="example.js">
export function hello() {
console.log('Hello World')
}
</Code>
Custom Containers
Create styled content containers:
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
Advanced Component Techniques
Client-Only Components
Some components should only run on the client side:
<!-- .vitepress/theme/components/ClientOnly.vue -->
<script>
export default {
data: () => ({ mounted: false }),
mounted() {
this.mounted = true
},
render() {
return this.mounted ? this.$slots.default() : null
}
}
</script>
Use it to wrap components that require browser APIs:
<ClientOnly>
<MapComponent />
</ClientOnly>
Async Components
Load components asynchronously for better performance:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import { defineAsyncComponent } from 'vue'
const HeavyComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.component('HeavyComponent', HeavyComponent)
}
}
Interactive Demos
Create interactive code demos:
<!-- .vitepress/theme/components/Demo.vue -->
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
code: String
})
const showCode = ref(false)
const toggleCode = () => {
showCode.value = !showCode.value
}
</script>
<template>
<div class="demo">
<div class="demo-preview">
<slot></slot>
</div>
<div class="demo-actions">
<button @click="toggleCode">{{ showCode ? 'Hide Code' : 'Show Code' }}</button>
</div>
<div v-if="showCode" class="demo-code">
<pre><code>{{ code }}</code></pre>
</div>
</div>
</template>
<style scoped>
.demo {
border: 1px solid #ddd;
border-radius: 4px;
margin: 1rem 0;
}
.demo-preview {
padding: 1.5rem;
}
.demo-actions {
padding: 0.5rem 1rem;
border-top: 1px solid #ddd;
}
.demo-code {
border-top: 1px solid #ddd;
padding: 1rem;
background-color: #f8f8f8;
}
</style>
Use it in your Markdown:
<Demo code="<button>Click Me</button>">
<button>Click Me</button>
</Demo>
Component Libraries
Using External Component Libraries
Install and use external Vue component libraries:
npm install element-plus
Register in your theme:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.use(ElementPlus)
}
}
Use in your Markdown:
# Using Element Plus
<el-button type="primary">Primary Button</el-button>
<el-date-picker v-model="date" type="date" placeholder="Pick a date" />
<script setup>
import { ref } from 'vue'
const date = ref(new Date())
</script>
Creating a Component Library
Document your own component library with VitePress:
- Create a demo component:
<!-- .vitepress/theme/components/ComponentDemo.vue -->
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
component: Object,
description: String
})
</script>
<template>
<div class="component-demo">
<div class="component-demo-example">
<component :is="component" />
</div>
<div class="component-demo-description">
<p>{{ description }}</p>
</div>
</div>
</template>
- Use it to showcase components:
<script setup>
import { Button } from 'my-component-library'
import ComponentDemo from '../.vitepress/theme/components/ComponentDemo.vue'
</script>
# Button Component
<ComponentDemo
:component="Button"
description="A customizable button component with various styles."
/>
## Props
| Name | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| type | String | 'default' | Button type |
| size | String | 'medium' | Button size |
Best Practices
Keep Components Simple: Focus on a single responsibility per component.
Optimize for SSR: Ensure components work with server-side rendering.
Use Client-Only When Needed: Wrap browser-only code in client-only components.
Provide Fallbacks: Include fallback content for components that might fail.
Document Props: Clearly document component props and events.
Style Isolation: Use scoped styles or CSS modules to prevent style leakage.
Accessibility: Ensure components are accessible with proper ARIA attributes.
Frequently Asked Questions
How do I use components only on specific pages?
Use dynamic imports in your page's <script setup>
section:
<script setup>
import { defineAsyncComponent } from 'vue'
const PageSpecificComponent = defineAsyncComponent(() =>
import('../components/PageSpecificComponent.vue')
)
</script>
# Page with Specific Component
<PageSpecificComponent />
Can I use components from npm packages?
Yes, install the package and register its components in your theme's index.js
:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import { ComponentFromPackage } from 'some-package'
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.component('ComponentFromPackage', ComponentFromPackage)
}
}
How do I handle component errors?
Use Vue's error handling with errorCaptured
or a global error handler:
// .vitepress/theme/index.js
export default {
...DefaultTheme,
enhanceApp({ app }) {
app.config.errorHandler = (err) => {
console.error('Global error:', err)
}
}
}
Related Resources
This document will be continuously updated. If you have any questions, please provide feedback through GitHub Issues.