Markdown
Provides real-time Markdown rendering, table of contents generation, and full-text search.
Basic Usage
Use src to pass a Markdown string and render the corresponding HTML output.
View Source
<template>
<vue-markdown :src="md" />
</template>
<script setup>
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>Parse HTML Tags
Use html to control whether HTML tags inside Markdown are parsed.
View Source
<template>
<div>
<p>
<label>
<input v-model="html" name="checkbox" type="checkbox" />
Enable html
</label>
</p>
<vue-markdown :src="md" :html="html" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const html = ref(true)
const md = `
# Lorem ipsum
<p style="background: rgba(9, 105, 218, 0.14); padding: 10px">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
</p>
`
</script>Sanitize HTML Tags
Use sanitize to sanitize HTML tags in the output to prevent XSS and other web attacks. Enabling sanitize may affect how some HTML tags are rendered. If the result is not what you expect and your security requirements are low, you can try disabling sanitize, but this is extremely risky. If you have strict security requirements, consider disabling html instead.
View Source
<template>
<div>
<h4>Markdown:</h4>
<pre style="background: #fff; overflow: auto"><code>{{ md }}</code></pre>
<h4>Output:</h4>
<vue-markdown :src="md" />
</div>
</template>
<script setup>
const md = `
<p style="background: rgba(9, 105, 218, 0.14); padding: 10px">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<iframe//src=jAva	script:alert(3)>def
</p>
`
</script>Preset Name
Use preset-name to quickly switch Markdown syntax rules. Three commonly used presets are built in: default (similar to GFM), commonmark (see CommonMark), and zero (disables all syntax rules).
TIP
Compared to markdown-it's default preset, the html option is enabled by default here.
View Source
<template>
<div>
<p>
<label>
Select a preset:
<select v-model="presetName" name="select">
<option v-for="item in options" :key="item" :value="item">{{ item }}</option>
</select>
</label>
</p>
<template v-for="item in options" :key="item">
<vue-markdown v-if="item === presetName" :src="md" :preset-name="item" />
</template>
</div>
</template>
<script setup>
import { ref } from 'vue'
const options = ['default', 'commonmark', 'zero']
const presetName = ref('default')
const md = `
| Preset Name | Description |
| ----------------------------------------------------------------------------------------------- | ----------------------------------------- |
| [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) | Similar to GFM |
| [commonmark](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) | See [CommonMark](https://commonmark.org/) |
| [zero](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) | Disables all syntax rules |
`
</script>markdown-it Plugins
Use plugins to pass markdown-it plugins. Two forms are supported: pass a single plugin directly, or pass an array of plugins where each item can be a plugin or a plugin-with-params tuple (e.g., [plugin, [plugin, param1, param2, ...], ...]).
View Source
<template>
<vue-markdown :src="md" :plugins="plugins" />
</template>
<script setup>
// npm i markdown-it-container
import container from 'markdown-it-container'
const md = `
# Lorem ipsum
::: example
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
:::
`
const plugins = [
[
container,
'example',
{
render: (tokens, idx) => {
return tokens[idx].nesting === 1 ? '<details><summary>Expand</summary>\n' : '</details>\n'
}
}
]
]
</script>Syntax Highlighting
Use highlight to syntax-highlight fenced code blocks based on their language. When a boolean is provided, highlight.js is used as the syntax highlighter and can be configured via highlight-options (see highlight.js configuration). If the default highlighting is not enough, highlight also supports providing a function to customize highlighting.
View Source
<template>
<div>
<p>
<label>
<input v-model="highlight" name="checkbox" type="checkbox" />
Enable highlight
</label>
</p>
<h4>Boolean:</h4>
<vue-markdown :src="md" :highlight="highlight" />
<h4>Function:</h4>
<vue-markdown :src="md" :highlight="highlight && customHighlight" />
</div>
</template>
<script setup>
// npm i highlight.js
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'
import { ref } from 'vue'
const highlight = ref(true)
const customHighlight = (str, language) => {
return hljs.highlight(str, { language }).value
}
const md = `
\`\`\` js
var foo = function (bar) {
return bar++;
};
console.log(foo(5));
\`\`\`
`
</script>Custom Highlight Class
Use lang-prefix to change the CSS class prefix used for code blocks, so you can customize highlight styles.
View Source
<template>
<div>
<p>
<label>
Select class prefix:
<select v-model="langPrefix" name="select">
<option value="custom-">Custom prefix: custom-</option>
<option value="language-">Default prefix: language-</option>
</select>
</label>
</p>
<vue-markdown :src="md" :lang-prefix="langPrefix" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const langPrefix = ref('custom-')
const md = `
\`\`\` js
var foo = function (bar) {
return bar++;
};
console.log(foo(5));
\`\`\`
`
</script>
<style>
.custom-js {
color: #666666 !important;
}
.custom-js .hljs-keyword {
color: #ab5959 !important;
}
.custom-js .hljs-title {
color: #59873a !important;
}
.custom-js .hljs-variable,
.custom-js .hljs-params {
color: #b07d48 !important;
}
.custom-js .hljs-string {
color: #b56959 !important;
}
</style>Linkify
Use linkify to automatically convert URL-like text in Markdown into links.
View Source
<template>
<div>
<p>
<label>
<input v-model="linkify" name="checkbox" type="checkbox" />
Enable linkify
</label>
</p>
<vue-markdown :src="md" :linkify="linkify" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const linkify = ref(true)
const md = `
Link: [https://www.example.com](https://www.example.com)
URL-like text: https://www.example.com
`
</script>Typographer
Use typographer to replace certain text in Markdown with typographic symbols. When typographer is enabled, you can also customize quotation marks via quotes, which is useful in multilingual environments.
View Source
<template>
<div>
<p>
<label>
<input v-model="typographer" name="checkbox" type="checkbox" />
Enable typographer
</label>
</p>
<p>
<label>
Enter quotes:
<input
v-for="(item, index) in quotes"
:key="item"
v-model="quotes[index]"
name="text"
style="width: 2em; margin: 4px"
/>
</label>
</p>
<vue-markdown :src="md" :typographer="typographer" :quotes="[...quotes]" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const typographer = ref(true)
const quotes = ref(['«', '»', '‹', '›'])
const md = `
Copyright symbol: (c)
Trademark: (tm)
Registered trademark: (r)
"This is a double-quote demo"
'This is a single-quote demo'
`
</script>Emoji
Use emoji to parse specific text in Markdown into emoji. In addition to boolean values, you can also pass an options object (see markdown-it-emoji options).
View Source
<template>
<vue-markdown :src="md" :emoji="emoji" />
</template>
<script setup>
const emoji = {
shortcuts: {
smiley: ':-)',
frowning: ':-(',
sunglasses: '8-)',
wink: ';)'
}
}
const md = `
Classic emojis: :wink: :cry: :laughing: :yum:
Custom shortcuts: :-) :-( 8-) ;)
`
</script>Heading Anchors
Use anchor to add unique IDs to all headings. This helps navigation components (such as Toc) perform anchor scrolling. When anchor is enabled, permalinks are enabled by default for all headings; you can toggle them with permalink. anchor also supports passing an options object or a function to customize heading rendering (see markdown-it-anchor options).
View Source
<template>
<div>
<h4>Default heading rendering:</h4>
<p>
<label>
<input v-model="permalink" name="checkbox" type="checkbox" />
Enable permalink (hover the heading to show the permalink symbol)
</label>
</p>
<vue-markdown :src="md" :permalink="permalink" />
<h4>Custom heading rendering:</h4>
<vue-markdown :src="md" :anchor="anchorOptions" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const permalink = ref(true)
const anchorOptions = (anchor) => ({
permalink: anchor.permalink.headerLink()
})
const md = `
# Lorem ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
`
</script>More Render Options
The rendering features support rich configuration such as custom Markdown styles, accessing the internal markdown-it instance, and breaks. For more details, see the Render. Its API also applies to the Markdown component.
View Source
<template>
<div>
<p>
<label>
Select a class name:
<select v-model="markdownClass" name="select">
<option value="custom-theme">Custom: custom-theme</option>
<option value="markdown-body">Default: markdown-body</option>
<option value="">No theme</option>
</select>
</label>
</p>
<vue-markdown :src="md" :markdown-class="markdownClass" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const markdownClass = ref('custom-theme')
const md = `
# Lorem ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
`
</script>
<style>
.custom-theme {
background: #fffffd;
}
.custom-theme * {
margin: 0;
}
.custom-theme h1 {
font-size: 2.4em;
padding-bottom: 0.3em;
border-bottom: 3px double #eee;
margin-bottom: 0.6em;
line-height: 1.35;
font-weight: bolder;
color: #456688;
}
.custom-theme p {
margin-bottom: 1.2em;
color: #383838;
}
.custom-theme a {
color: #456688;
text-decoration: none;
}
</style>Search
Use search to enable searching. You can also bind the keyword via keyword. When the keyword is present, it will automatically scroll to the match and highlight it.
View Source
<template>
<vue-markdown
v-model:keyword="keyword"
v-model:search="search"
style="height: 436px; overflow: auto"
:src="md"
/>
</template>
<script setup>
import { ref } from 'vue'
const search = ref(true)
const keyword = ref('or')
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>More Search Options
The search feature supports rich configuration such as border, size, and disabled. For more details, see the Search. When using it through the Markdown component, prefix Search props in its API with search-.
View Source
<template>
<div>
<p>
<label style="margin-right: 10px">
Enter index:
<input v-model="index" name="number" type="number" style="width: 4em" />
</label>
<button @click="markdownRef.searchToggle(index)">Go</button>
</p>
<p>Current index (starting at 0): {{ safeIndex }}</p>
<vue-markdown
v-model:keyword="keyword"
v-model:search="search"
ref="markdownRef"
style="height: 436px; overflow: auto"
:src="md"
@search-index-change="safeIndex = $event"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const markdownRef = ref(null)
const search = ref(true)
const keyword = ref('or')
const index = ref(0)
const safeIndex = ref(0)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>TOC
Use toc to enable the TOC feature. The component generates a TOC based on the rendered content.
View Source
<template>
<vue-markdown toc top-offset="64" :src="md" />
</template>
<script setup>
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>More TOC Options
The TOC feature supports rich configuration such as plain text, ordered list, and heading level range. For more details, see the Toc. When using it through the Markdown component, prefix Toc props in its API with toc-.
View Source
<template>
<div>
<p>
<label>
Select start-level:
<select v-model="startLevel" name="select">
<option v-for="key in options" :key="key" :value="key">h{{ key }}</option>
</select>
</label>
</p>
<p>
<label>
Select end-level:
<select v-model="endLevel" name="select">
<option v-for="key in options" :key="key" :value="key">h{{ key }}</option>
</select>
</label>
</p>
<vue-markdown
toc
style="height: 436px; overflow: auto"
:src="md"
:toc-start-level="startLevel"
:toc-end-level="endLevel"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const startLevel = ref(2)
const endLevel = ref(5)
const options = Array.from({ length: 6 }, (_, index) => index + 1)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>Action Buttons
Use show-btn to display a group of action buttons at the bottom of the component, used to toggle the visibility of Search and TOC. When set to true, both search and TOC buttons are shown by default. When set to an array or object, you can customize which buttons are displayed.
View Source
<template>
<div>
<p>
<label>
<input v-model="showBtn.search" name="checkbox" type="checkbox" />
Show search button
</label>
<label>
<input v-model="showBtn.toc" name="checkbox" type="checkbox" />
Show TOC button
</label>
</p>
<vue-markdown :src="md" :show-btn="showBtn" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const showBtn = ref({ toc: true, search: true })
const md = `
# Lorem ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi maximus elit fermentum pellentesque vehicula. Suspendisse potenti. Donec iaculis consectetur erat nec placerat. Suspendisse facilisis justo sit amet hendrerit sollicitudin. Suspendisse commodo malesuada massa, ac elementum risus. Ut eu facilisis neque. Fusce tincidunt, ligula vitae eleifend venenatis, purus purus ultrices purus, nec maximus tellus lectus nec leo. Sed auctor magna sed quam dapibus dapibus. Nullam ornare ultricies sem, a iaculis sapien volutpat euismod. Sed ac dictum nulla. Duis euismod tellus vitae diam hendrerit, sit amet vestibulum mauris rhoncus.
`
</script>Sticky Offset
All helper components use sticky positioning. Use top-offset to control the sticky top offset for the search and TOC, and bottom-offset to control the sticky bottom offset for the action buttons. When nested inside multiple scroll containers, sticky behavior and offsets only apply to the nearest scroll container.
View Source
<template>
<div style="position: relative">
<header
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 5;
"
>
Fixed header
</header>
<div style="height: 492px; overflow: auto">
<vue-markdown
toc
search
show-btn
style="margin: 56px 0"
top-offset="56"
bottom-offset="56"
:src="md"
/>
</div>
<footer
style="
width: 100%;
background: #0969da;
position: absolute;
bottom: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 5;
"
>
Fixed footer
</footer>
</div>
</template>
<script setup>
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>Scroll Offset
By default, top-offset is also used as the scroll offset for TOC anchor navigation. To set a TOC offset separately, use toc-offset. Search index navigation does not inherit this behavior; use search-offset to set it explicitly. Both toc-offset and search-offset support numbers and string positions (center, start, end, nearest). When nested inside multiple scroll containers, scrolling behavior and offsets only apply to the nearest scroll container.
TIP
When the search is visible and toc-offset is a number or start, the TOC will automatically add the search input height as an extra scroll offset.
View Source
<template>
<div>
<h4>Default:</h4>
<div style="flex: auto; position: relative; margin-bottom: 16px">
<header
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 5;
"
>
Fixed header
</header>
<div style="height: 436px; overflow: auto">
<vue-markdown
v-model:keyword="keyword"
toc
search
style="margin-top: 56px"
top-offset="56"
:src="md"
/>
</div>
</div>
<h4>Number:</h4>
<div style="flex: auto; position: relative; margin-bottom: 16px">
<header
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 5;
"
>
Fixed header
</header>
<div
style="
position: absolute;
top: 160px;
color: #0969da;
padding: 10px;
box-sizing: border-box;
z-index: 1;
border-bottom: 2px solid #0969da;
width: 100%;
font-weight: bold;
text-align: center;
"
>
Scroll offset marker
</div>
<div style="height: 436px; overflow: auto">
<!-- 57 is the height of the search input itself -->
<vue-markdown
v-model:keyword="keyword"
toc
search
style="margin-top: 56px"
top-offset="56"
toc-offset="150"
:search-offset="150 + 57"
:src="md"
/>
</div>
</div>
<h4>String:</h4>
<div style="flex: auto; position: relative; margin-bottom: 16px">
<header
style="
width: 100%;
background: #0969da;
position: absolute;
top: 0;
color: #fff;
padding: 16px 32px;
box-sizing: border-box;
z-index: 5;
"
>
Fixed header
</header>
<div style="height: 436px; overflow: auto">
<vue-markdown
v-model:keyword="keyword"
toc
search
style="margin-top: 56px"
top-offset="56"
toc-offset="end"
search-offset="end"
:src="md"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const keyword = ref('or')
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>Mobile Layout
Use mini-screen-width to set the width threshold for mobile devices. When the component width is less than or equal to this value, it will automatically switch to the mobile layout.
View Source
<template>
<div style="overflow: auto">
<p>
<label>
Adjust mini-screen-width:
<input v-model="miniScreenWidth" style="width: 4em" name="number" type="number" min="230" />
</label>
</p>
<p>
<label>
Adjust component width:
<input v-model="componentWidth" style="width: 4em" name="number" type="number" min="230" />
</label>
</p>
<vue-markdown
toc
show-btn
:style="{ height: '436px', overflow: 'auto', width: `${componentWidth}px` }"
:src="md"
:mini-screen-width="miniScreenWidth"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const miniScreenWidth = ref(768)
const componentWidth = ref(768)
const md = `
# h1 Heading 8-)
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
---
***
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Strikethrough~~
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with \`+\`, \`-\`, or \`*\`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as \`1.\`
Start numbering with offset:
57. foo
1. bar
## Tables
| Option | Description |
| ------ | ----------- |
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
Right aligned columns
| Option | Description |
| ------:| -----------:|
| data | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
`
</script>API
Props
| Name | Description | Type | Default |
|---|---|---|---|
| src | Markdown string | string / number | '' |
| html | Whether to parse HTML tags in Markdown | boolean | true |
| sanitize | Whether to sanitize HTML tags in the output. Accepts a boolean or DOMPurify options | boolean / SanitizeOptions | true |
| preset-name | Markdown preset name | 'default' | 'commonmark' | 'zero' | default |
| plugins | markdown-it plugins | PluginSimple / Array<PluginSimple | [PluginWithParams, ...any[]]> | [] |
| inline | Whether to enable inline mode | boolean | false |
| xhtml-out | Whether to generate XHTML-compliant output | boolean | false |
| breaks | Whether to render \n as <br> | boolean | false |
| highlight | Whether to enable syntax highlighting for code blocks | boolean / (str: string, lang: string, attrs: string) => string | true |
| highlight-options | Syntax highlighting options. Only effective when highlight is true. See highlight.js configuration | HLJSOptions | - |
| lang-prefix | CSS class prefix for code blocks | string | language- |
| linkify | Whether to convert URL-like text into links | boolean | false |
| typographer | Whether to replace certain text with common typographic symbols | boolean | false |
| quotes | Custom quotation marks. Only effective when typographer is enabled | string / Array<string> | “”‘’ |
| emoji | Whether to parse specific text into emojis. Accepts a boolean or markdown-it-emoji options | boolean / EmojiOptions | true |
| anchor | Heading anchor configuration. Accepts a boolean, markdown-it-anchor options, or a function | boolean / AnchorOptions / (anchor: Anchor) => AnchorOptions | true |
| permalink | Whether to enable permalinks. Only effective when anchor is true | boolean | true |
| markdown-class | Custom Markdown CSS class | string | markdown-body |
| show-btn | Whether to show the bottom action buttons | boolean / Array<('search' | 'toc')> / { search?: boolean; toc?: boolean } | false |
| top-offset | Global top offset: sticky top offset and the default scroll offset for TOC anchor navigation | number / string | 0 |
| bottom-offset | Global bottom offset for sticky bottom positioning | number / string | 0 |
| mini-screen-width | Mobile width threshold. When the component width is less than or equal to this value, it switches to the mobile layout | number / string | 768 |
| v-model:search | Whether to show the search | boolean | false |
| v-model:keyword | Search keyword | string / number | '' |
| search-clearable | Whether to show the clear button in the search | boolean | true |
| search-close-icon | Whether to show the close button in the search | boolean | true |
| search-border | Whether to show the bottom border of the search | boolean | true |
| search-size | Search input size | 'huge' | 'large' | 'normal' | 'small' | huge |
| search-disabled | Whether to disable the search | boolean | false |
| search-placeholder | Search input placeholder text | string | - |
| search-offset | Scroll offset when switching the search match index | number / 'start'|'end'|'center'|'nearest' | center |
| search-smooth | Whether to enable smooth scrolling when navigating between search matches | boolean | false |
| search-input-attrs | Attributes passed to the internal search input element | object | {} |
| v-model:toc | Whether to show the TOC | boolean | false |
| toc-plain-text | Whether to generate a plain-text TOC | boolean | false |
| toc-ordered-list | Whether to generate an ordered TOC | boolean | false |
| toc-start-level | Start heading level for the TOC | number / string | 1 |
| toc-end-level | End heading level for the TOC | number / string | 6 |
| toc-ignore | Heading levels to ignore in the TOC | Array<number | string> | [] |
| toc-empty-text | Text displayed when the TOC is empty | string | No Data |
| toc-offset | Scroll offset during TOC anchor navigation | number / 'start'|'end'|'center'|'nearest' | start |
| toc-smooth | Whether to enable smooth scrolling when navigating via the TOC | boolean | false |
| toc-change-hash | Whether to update the page hash when navigating via the TOC | boolean | true |
Events
| Name | Description | Arguments |
|---|---|---|
| env-change | Triggered when env in markdown-it changes | value: {} |
| search-input | Triggered when the search keyword changes | event: Event |
| search-blur | Triggered when the search input loses focus | event: FocusEvent |
| search-focus | Triggered when the search input gains focus | event: FocusEvent |
| search-change | Triggered only when the search input blurs or Enter is pressed | event: Event |
| search-clear | Triggered when clicking the search clear button | - |
| search-close | Triggered when clicking the search close button | - |
| search-step-click | Triggered when clicking the search previous/next buttons | value: 'prev' | 'next' |
| search-total-change | Triggered when the total search match count changes | value: number |
| search-index-change | Triggered when the current search match index changes | value: number |
| toc-click | Triggered when clicking a TOC item. For arguments see TocItem | tocItem: TocItem |
| toc-change | Triggered when the active TOC item changes | id: string |
Expose
| Name | Description | Type |
|---|---|---|
| mdInstance | Get the internal markdown-it instance | MarkdownIt |
| htmlStr | Get the parsed HTML string | string |
| searchFocus | Focus the search input | () => void |
| searchBlur | Blur the search input | () => void |
| searchClear | Clear the search keyword | () => void |
| searchToggle | Switch the current search match index | (index: number | 'prev' | 'next', ignoreDisabled?: boolean) => void |
| searchRefresh | Refresh search results manually | (resetIndex?: boolean) => void |
| tocScrollTo | Scroll to a given heading in the TOC | (href: string) => void |
| tocRefresh | Regenerate the TOC | () => void |