Using Vue in Markdown

Browser API Access Restrictions

Because VuePress applications are server-rendered in Node.js when generating static builds, any Vue usage must conform to the universal code requirements. In short, make sure to only access Browser / DOM APIs in beforeMount or mounted hooks.

If you are using or demoing components that are not SSR-friendly (for example, contain custom directives), you can wrap them inside the built-in <ClientOnly> component:


Note this does not fix components or libraries that access Browser APIs on import. To use code that assumes a browser environment on import, you need to dynamically import them in proper lifecycle hooks:

export default {
  mounted () {
    import('./lib-that-access-window-on-import').then(module => {
      // use code

If your module export default a Vue component, you can register it dynamically:

  <component v-if="dynamicComponent" :is="dynamicComponent"></component>

export default {
  data() {
    return {
      dynamicComponent: null

  mounted () {
    import('./lib-that-access-window-on-import').then(module => {
      this.dynamicComponent = module.default

Also see:



Each Markdown file is first compiled into HTML and then passed on as a Vue component to vue-loader. This means you can use Vue-style interpolation in text:


{{ 1 + 1 }}




Directives also work:


<span v-for="i in 3">{{ i }} </span>


1 2 3 

Access to Site & Page Data

The compiled component does not have any private data but does have access to the site metadata. For example:


{{ $page }}


  "path": "/using-vue.html",
  "title": "Using Vue in Markdown",
  "frontmatter": {}


By default, fenced code blocks are automatically wrapped with v-pre. To display raw mustaches or Vue-specific syntax inside inline code snippets or plain text, you need to wrap a paragraph with the v-pre custom container:


::: v-pre
`{{ This will be displayed as-is }}`


{{ This will be displayed as-is }}

Using Components

Any *.vue files found in .vuepress/components are automatically registered as global, async components. For example:

└─ .vuepress
   └─ components
      ├─ demo-1.vue
      ├─ OtherComponent.vue
      └─ Foo
         └─ Bar.vue

Inside any Markdown file you can then directly use the components (names are inferred from filenames):


Hello this is <demo-1>

This is another component

Hello this is <Foo-Bar>


Make sure a custom component’s name either contains a hyphen or is in PascalCase. Otherwise it will be treated as an inline element and wrapped inside a <p> tag, which will lead to hydration mismatch because <p> does not allow block elements to be placed inside it.

Using Components In Headers

You can use Vue components in the headers, but note the difference between the following syntaxes:

Markdown Output HTML Parsed Header
 # text <Tag/> 
<h1>text <Tag/></h1> text
 # text `<Tag/>` 
<h1>text <code>&lt;Tag/&gt;</code></h1> text <Tag/>

The HTML wrapped by <code> will be displayed as-is; only the HTML that is not wrapped will be parsed by Vue.


The output HTML is accomplished by markdown-it, while the parsed headers are handled by VuePress (and used for both the sidebar and document title).

Using Pre-processors

VuePress has built-in webpack support for the following pre-processors: sass, scss, less, stylus and pug. All you need to do is installing the corresponding dependencies. For example, to enable sass:

yarn add -D sass-loader node-sass

Now you can use the following in Markdown and theme components:

<style lang="sass">
  font-size: 20px

Using <template lang="pug"> requires installing pug and pug-plain-loader:

yarn add -D pug pug-plain-loader


If you are a Stylus user, you don’t need to install stylus and stylus-loader in your project; VuePress uses Stylus internally.

For pre-processors that do not have built-in webpack config support, you will need to extend the internal webpack config and install the necessary dependencies.

Script & Style Hoisting

Sometimes you may need to apply some JavaScript or CSS only to the current page. In those cases, you can directly write root-level <script> or <style> blocks in the Markdown file. These will be hoisted out of the compiled HTML and used as the <script> and <style> blocks for the resulting Vue single-file component:

Built-In Components

The indicator is used to denote external links. In VuePress, this component has been followed by every external link.

ClientOnly stable

See Browser API Access Restrictions.


  • Props:

  • Usage

Specify a specific slot for a specific page (.md) for rendering. This is useful when using a Custom Layout or Writing a theme:


Also see:

Badge beta default theme

  • Props:

    • text - string
    • type - string, optional value: "tip"|"warning"|"error", defaults to "tip".
    • vertical - string, optional value: "top"|"middle", defaults to "top".
  • Usage:

You can use this component in a header to add some status for an API:

### Badge <Badge text="beta" type="warning"/> <Badge text="default theme"/>

Also see: