---
url: /guide.md
---
# What is VueMarkik?
**VueMarkik** (pronounced *view-mark-eek*, IPA /vjuː mɑːrk ik/) is a mini component library for Vue.js with components that take a markdown string and render it to Vue elements without `v-html`. It is built on top of [unified](https://github.com/unifiedjs/unified), using [remark](https://github.com/remarkjs/remark) to parse markdown, and [rehype](https://github.com/rehypejs/rehype) to render it to Vue components. Raw HTML is disabled, final HAST is sanitized after plugins, and unsafe URL protocols are filtered by default; see the [security guide](./security) for the complete trust boundary.
Just want to use it? Skip to [Getting Started](./getting-started).
Working with LLM output? See [Streaming Markdown](./streaming-markdown).
The name **VueMarkik** comprises the words *Vue Markdown* with the Armenian diminutive *-ik* (*-իկ*), which turns nouns into smaller, cuter, or familiar versions of themselves. Thus **VueMarkik** is a small friendly plugin for rendering markdown in Vue.js.
## Features
* **Markdown Extensions**
VueMarkik can be configured with [remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins) to change how markdown is transformed, enabling support for markdown syntax extensions such as GFM and MDX.
* **Custom Rendering**
VueMarkik can be configured with [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins) to change how markdown is rendered, for example syntax highlighting with [Shiki](https://shiki.matsu.io/), diagrams with [mermaid](https://mermaid.js.org/), and math rendering with [KaTeX](https://katex.org/).
* **Custom Vue Components**
To further customize the rendered markdown, you can provide custom Vue components that will be used instead of standard HTML elements, or use template slots for dynamic customization. For example, a custom component or slot for `
` can customise the rendering of `# hola`.
* **Streaming-Friendly Recovery**
When markdown is updated incrementally, such as from LLM output, VueMarkik can preserve the last successful render and emit `render-error` instead of flooding the console with warnings.
---
---
url: /guide/getting-started.md
---
# Getting Started
## Installation
Install using your package manager:
::: code-group
```sh [npm]
npm install vuemarkik
```
```sh [yarn]
yarn add vuemarkik
```
```sh [pnpm]
pnpm add vuemarkik
```
```sh [bun]
bun add vuemarkik
```
```sh [deno]
deno add npm:vuemarkik
```
:::
## Simple Rendering
To render a markdown string, import the `Markdown` component and pass the string to the `text` prop:
```html
```
This renders the following:
::: raw
:::
## What's Next?
Learn how to customize and extend VueMarkik:
* **[Security](./security)** - Review the default URL policy and plugin trust boundary
* **[Migrating to v2](./migrating-to-v2)** - Upgrade existing plugin integrations to the safe default
* **[Custom Vue Components](./custom-vue-components)** - Use your own components or slots for rendering
* **[Remark & Rehype Plugins](./remark-rehype-plugins)** - Extend markdown syntax and rendering
* **[Streaming Markdown](./streaming-markdown)** - Handle incremental LLM output without console spam
Or explore specific examples:
* **[GitHub Flavored Markdown](./github-flavored-markdown)** - Tables, task lists, strikethrough, and more
* **[Syntax Highlighting](./syntax-highlighting)** - Code highlighting with Shiki
* **[Mermaid Diagrams](./mermaid)** - Render diagrams and flowcharts
* **[Math with KaTeX](./katex)** - Display mathematical equations
---
---
url: /guide/security.md
---
# Security
VueMarkik is safe by default for untrusted markdown under the boundary
documented here. It keeps raw HTML disabled, runs user-configured remark and
rehype plugins, sanitizes their final HAST output, applies a URL policy, and
only then converts the tree to Vue VNodes without `v-html` or
`dangerouslySetInnerHTML`.
## Safe mode
`securityMode="safe"` is the default for `Markdown`, `MarkdownAsync`, and
`MarkdownHooks`.
The rendering pipeline is:
```text
markdown
-> remark parser and plugins
-> remark-rehype
-> rehype plugins
-> final HAST sanitizer
-> URL transform
-> Vue VNodes
```
The final sanitizer uses `rehype-sanitize` with a GitHub-style allowlist. It:
* Allows normal CommonMark and GFM elements and properties.
* Removes scripting, embedded browsing contexts, event properties, inline
styles, and unknown metadata.
* Prefixes DOM-clobbering `id` and `name` values.
* Restricts URL protocols.
* Sanitizes the HAST node and properties passed to custom components and slots.
The default URL policy allows relative, fragment, query, `http`, `https`,
`mailto`, and `tel` URLs. Other explicit protocols, including `javascript`,
`vbscript`, and `data`, are removed.
## Trusted mode
Use trusted mode only when both the markdown and the configured plugins are
trusted:
```vue
```
Trusted mode skips final-HAST sanitization and preserves legacy plugin output.
The URL policy still runs, and raw HTML in markdown remains disabled.
This mode exists for compatibility with plugins such as Shiki, KaTeX, and
Mermaid that generate broad classes, inline styles, SVG, or data URLs. It is
not a safe fallback for arbitrary user content.
## Plugin compatibility
| Integration | Safe mode | Trusted mode |
| ------------------------ | ---------------------------------------------------------------------- | ----------------------- |
| CommonMark | Preserved | Preserved |
| GitHub Flavored Markdown | Preserved by the default schema | Preserved |
| Shiki | Code remains readable; highlighting classes and styles are removed | Full highlighted output |
| KaTeX | Math text remains readable; typesetting classes and styles are removed | Full typeset output |
| Mermaid | Diagram source remains; rendered/enhanced output is removed | Full plugin output |
Plugin code always executes with the host application's privileges. Final-HAST
sanitization controls its rendered output; it does not sandbox the plugin
itself.
## Custom schemas
All renderers accept `sanitizeSchema`. Start from the exported default rather
than replacing it accidentally:
```ts
import { defaultSanitizeSchema, type SanitizeSchema } from 'vuemarkik';
const schema: SanitizeSchema = {
...defaultSanitizeSchema,
attributes: {
...defaultSanitizeSchema.attributes,
code: [
...(defaultSanitizeSchema.attributes?.code ?? []),
['className', 'language-javascript'],
],
},
};
```
```vue
```
A custom schema changes the security boundary. In particular, do not broadly
allow `style`, event properties, scripts, embedded browsing contexts, SVG, or
data URLs merely to preserve a plugin's appearance. Prefer a narrowly tested
allowlist or trusted mode for content that is genuinely trusted.
## Custom URL policies
All rendering components accept `urlTransform`:
```vue
```
The callback receives the URL value, HAST property name, and a read-only
TypeScript view of the current HAST element, which has been sanitized in safe
mode. Return a string to keep or rewrite the property, or `undefined` to remove
it.
A custom transform replaces the default URL policy and therefore changes the
security boundary. To extend the default safely, call it first:
```ts
import { defaultUrlTransform, type UrlTransform } from 'vuemarkik';
const transformUrl: UrlTransform = (url) => {
const safeUrl = defaultUrlTransform(url);
return safeUrl ? addApplicationTracking(safeUrl) : undefined;
};
```
## Remaining trust boundary
Safe mode does not promise:
* Safety of the JavaScript executed by plugins, custom components, or slots.
* Safety after a custom schema or URL transform broadens the defaults.
* Privacy or safety of remote resources reached through allowed URLs.
* Protection from denial of service caused by extremely large or pathological
markdown or expensive plugins.
Apply application-level input-size and update-rate limits when content is
attacker-controlled. Move expensive processing into an appropriately isolated
worker when availability is important.
## Upstream security model
VueMarkik follows the unified ecosystem's guidance:
* [remark security](https://github.com/remarkjs/remark#security)
* [remark-rehype security](https://github.com/remarkjs/remark-rehype#security)
* [rehype security](https://github.com/rehypejs/rehype#security)
* [hast-util-to-jsx-runtime security](https://github.com/syntax-tree/hast-util-to-jsx-runtime#security)
* [rehype-sanitize security](https://github.com/rehypejs/rehype-sanitize#security)
These projects recommend sanitizing user-controlled HAST after the last unsafe
operation. VueMarkik owns that final boundary in safe mode so consumer plugin
ordering cannot bypass it.
## Reporting a vulnerability
Please use
[GitHub private vulnerability reporting](https://github.com/taugr/vuemarkik/security)
instead of opening a public issue.
---
---
url: /guide/migrating-to-v2.md
---
# Migrating to v2
VueMarkik v2 makes final-HAST sanitization the default. Normal CommonMark and
GitHub Flavored Markdown continue to render, while plugin-created elements,
properties, classes, and styles outside the safe schema are removed.
## Upgrade and run your tests
Install VueMarkik v2:
```sh
pnpm add vuemarkik@^2
```
Exercise every markdown source, plugin, custom component, slot, browser-rendered
surface, and SSR surface in your application. Pay particular attention to
syntax highlighting, math, diagrams, custom classes, inline styles, SVG, and
embedded content.
## Choose a migration path
### Keep safe mode
No prop is required:
```vue
```
Prefer this path for user content, LLM output, comments, documentation input,
and any markdown crossing a trust boundary.
If a plugin loses nonessential presentation, keep safe mode and style the
remaining semantic markup yourself. If specific properties are essential,
extend `defaultSanitizeSchema` with the smallest tested allowlist.
### Temporarily use trusted mode
To preserve VueMarkik 1.x plugin output:
```vue
```
Only use this with content and plugins you trust. Record each trusted-mode use
as a security exception and test a path back to safe mode.
Current compatibility:
* GFM works with the default safe schema.
* Shiki highlighting requires trusted mode unless you maintain a narrow custom
schema for its generated output.
* KaTeX typesetting requires trusted mode unless you maintain a narrow custom
schema.
* Mermaid rendering requires trusted mode; its SVG and data-URL strategies are
intentionally outside the default schema.
## Review custom URL transforms
The default URL policy allows relative URLs and the `http`, `https`, `mailto`,
and `tel` protocols. A custom `urlTransform` replaces that policy. Call
`defaultUrlTransform` inside your custom callback unless you deliberately own a
different security policy.
## Review custom components and slots
In safe mode, custom components and slots receive sanitized HAST nodes and
element properties. Their own Vue code remains trusted and can still create
unsafe behavior, so review code that forwards URLs, creates HTML, loads remote
resources, or executes content.
## Verify before removing trusted mode
Before declaring an application migrated:
1. Test representative and adversarial markdown in the browser and under SSR.
2. Verify unsafe elements, event properties, styles, and protocols are absent.
3. Confirm documented plugin output remains usable.
4. Confirm custom components receive only the expected sanitized properties.
5. Remove temporary trusted-mode exceptions where possible.
See [Security](./security) for the full threat model and schema guidance.
---
---
url: /guide/remark-rehype-plugins.md
---
# Plugins
VueMarkik utilizes *remark* and *rehype* to parse and process markdown to Vue components. Both of these projects have a rich ecosystem of plugins, enabling support of a variety of markdown formats and extensions, and the ability to transform the rendered output in any desired way.
::: warning Security boundary
Plugins execute application code and can add arbitrary HAST elements and
properties. Safe mode sanitizes their final output, but the plugin code itself
still runs with your application's privileges. Only use plugins you trust and
review the [security guide](./security) when the markdown source is untrusted.
If a plugin's presentation is removed by the default schema, audit it before
using `security-mode="trusted"` or a custom schema.
:::
## Remark Plugins
Remark plugins can inspect and transform Markdown. Their most common use is to support extensions to the CommonMark syntax, such as GitHub Flavored Markdown (GFM) and MDX.
The remark repo maintains [lists of available plugins](https://github.com/remarkjs/remark?tab=readme-ov-file#plugins).
### Examples
* [GitHub Flavored Markdown](./github-flavored-markdown.md)
## Rehype Plugins
Rehype plugins change the HTML that is rendered from markdown. Common scenarios include code syntax highlighting, diagram rendering, and math typesetting.
The rehype repo maintains [lists of available plugins](https://github.com/rehypejs/rehype?tab=readme-ov-file#plugins).
### Examples
* [Syntax Highlighting](./syntax-highlighting.md)
* [Mermaid Diagrams](./mermaid.md)
* [KaTeX Math](./katex.md)
---
---
url: /guide/custom-vue-components.md
---
# Custom Vue Components
VueMarkik allows you to customize how markdown elements are rendered by providing your own Vue components. This gives you complete control over the styling and behavior of any HTML element in your rendered markdown.
There are two approaches to customize markdown rendering:
1. **Using the `components` prop** - Pass custom Vue components defined in separate files
2. **Using Vue template slots** - Define custom rendering inline with template slots
Both approaches give you full control over styling and behavior. Choose based on whether you want to reuse components across multiple places (use `components` prop) or keep customization inline (use slots).
::: tip Precedence
If you define both a custom component (via `components` prop) and a slot for the same HTML element, **the slot will take precedence**. This allows you to override component-level customizations on a per-instance basis.
:::
## Using Custom Vue Components
The `components` prop accepts an object mapping HTML element names to Vue components. This is ideal when you want to reuse the same custom styling across multiple markdown instances.
### Example: Custom H1 Component
First, create a Vue component for your custom element:
```vue
```
::: tip
The `` element is required to render the child nodes (text content, nested elements, etc.) of the markdown element. Without it, your custom component would be empty.
:::
Then use it by passing it to the `components` prop:
```vue
```
**Live Demo:**
::: raw
:::
### Example: Custom Code Component
You can customize any HTML element, including inline code:
```vue
```
Use it the same way:
```vue
```
**Live Demo:**
::: raw
:::
## Using Vue Template Slots
Instead of creating separate component files, you can use Vue template slots to customize rendering inline. This approach uses the `MarkdownChildNodes` component to render the element's children.
### Example: Custom H1 with Slots
```vue
```
Slot props always include `childMarkdown`, which contains the rendered children. `MarkdownChildNodes` renders those children for you, and other element props such as `href` are passed through alongside it.
**Live Demo:**
::: raw
\
### Example: Custom Code with Slots
```vue
```
**Live Demo:**
::: raw
\
:::
## Combining Both Approaches
You can mix both approaches - use the `components` prop for some elements and slots for others:
::: tip Precedence
If you define both a custom component (via `components` prop) and a slot for the same HTML element, **the slot will take precedence**. This allows you to override component-level customizations on a per-instance basis.
:::
```vue
```
**Live Demo:**
::: raw
\
:::
---
---
url: /guide/github-flavored-markdown.md
---
# GitHub Flavoured Markdown (GFM)
GFM includes a variety of markdown syntax extensions including strike-through, tables, tasklists, and more. To extend VueMarkik with GFM first install the `remark-gfm` plugin:
::: code-group
```sh [npm]
npm install remark-gfm
```
```sh [yarn]
yarn add remark-gfm
```
```sh [pnpm]
pnpm add remark-gfm
```
```sh [bun]
bun add remark-gfm
```
```sh [deno]
deno add npm:remark-gfm
```
:::
You can then provide it to the `remark-plugins` prop as in the following example:
```vue
```
This renders the following output:
:::raw
:::
---
---
url: /guide/syntax-highlighting.md
---
# Syntax Highlighting
Syntax highlighting for code blocks can be added through rehype plugins such as shiki, prism, and highlight.js. See the respective documentation pages for configuration and settings for each of these plugins.
::: warning Security mode
Shiki generates broad classes and inline styles that the default safe schema
removes. The examples on this page use `security-mode="trusted"` and should only
render trusted markdown. For untrusted content, keep safe mode and accept
unstyled semantic code output, or maintain a narrowly audited custom schema.
:::
## Shiki
To illustrate how to add syntax highlighting the following example shows how to install and configure shiki with VueMarkik. The steps for other syntax highlighting plugins is similar.
First install the shiki rehype plugin:
::: code-group
```sh [npm]
npm install @shikijs/rehype
```
```sh [yarn]
yarn add @shikijs/rehype
```
```sh [pnpm]
pnpm add @shikijs/rehype
```
```sh [bun]
bun add @shikijs/rehype
```
```sh [deno]
deno add npm:@shikijs/rehype
```
:::
By default Shiki runs asyncronously as it loads stylesheets dynamically based on which programming language it needs to render for. VueMarkik provides two components to support async rendering: the `MarkdownAsync` component uses the experimental suspense feature in Vue, and `MarkdownHooks` which uses a callback to render markdown without depending on the suspense feature.
In this example we use the `MarkdownHooks` component to render code blocks for multiple languages.
```vue
```
This renders as:
::: raw
:::
The configuration above lets Shiki lazily load the languages you specify, apply GitHub light and dark themes automatically, and fall back to Markdown highlighting when a language is unknown. Adjust the `langs`, `themes`, or other options to match the languages and styling needs of your project.
---
---
url: /guide/mermaid.md
---
# Mermaid Diagrams
Mermaid lets you describe flow charts, sequence diagrams, mind maps, and more using a compact text syntax. VueMarkik can render these diagrams by adding the `rehype-mermaid` plugin to your Markdown pipeline.
::: warning Security mode
Mermaid's rendered SVG and data-URL output is intentionally outside the
default safe schema. The examples on this page use
`security-mode="trusted"` and should only render trusted diagram source.
:::
## Install rehype-mermaid
::: code-group
```sh [npm]
npm install rehype-mermaid
```
```sh [yarn]
yarn add rehype-mermaid
```
```sh [pnpm]
pnpm add rehype-mermaid
```
```sh [bun]
bun add rehype-mermaid
```
```sh [deno]
deno add npm:rehype-mermaid
```
:::
## Render diagrams in VueMarkik
Once the plugin is installed, pass it to `MarkdownHooks` (or `MarkdownAsync`) through the `rehypePlugins` prop. Any fenced code block with the `mermaid` language tag will be transformed into an interactive diagram.
```vue
```
This renders as:
::: raw
:::
The default configuration renders inline SVGs. You can switch strategies (`'img-png'`, `'img-svg'`, `'inline-svg'`, or `'pre-mermaid'`), add responsive dark-mode images with `dark: true`, or pass a `mermaidConfig` object for diagram-level tweaks. Refer to the `rehype-mermaid` documentation for the full list of supported options.
---
---
url: /guide/katex.md
---
# KaTeX Math
Use KaTeX to typeset inline math (`$...$`) and display math (`$$...$$`) inside your VueMarkik content. The pipeline combines two plugins:
* `remark-math` parses inline and block level LaTeX expressions.
* `rehype-katex` renders those nodes into HTML markup using KaTeX.
## Install the math plugins
::: code-group
```sh [npm]
npm install remark-math rehype-katex katex
```
```sh [yarn]
yarn add remark-math rehype-katex katex
```
```sh [pnpm]
pnpm add remark-math rehype-katex katex
```
```sh [bun]
bun add remark-math rehype-katex katex
```
```sh [deno]
deno add npm:remark-math npm:rehype-katex npm:katex
```
:::
Import KaTeX’s stylesheet once in your app entry point (for example `main.ts`) so the rendered math picks up the correct fonts:
```ts
import 'katex/dist/katex.min.css';
```
## Render math in VueMarkik
Pass both plugins to VueMarkik through the `remarkPlugins` and `rehypePlugins` props. Math enclosed in dollar signs will be transformed automatically. The example below uses `String.raw` so LaTeX backslashes can be written exactly once.
::: warning Security mode
KaTeX generates broad classes and inline styles that the default safe schema
removes. The examples on this page use `security-mode="trusted"` and should only
render trusted markdown. KaTeX's own `trust` option expands its security surface
further and should remain disabled for untrusted input.
:::
```vue
```
This renders as:
::: raw
:::
## Configure KaTeX output
`rehype-katex` accepts any of the [KaTeX options](https://katex.org/docs/options.html). Pass them as the second item in the plugin tuple to enable features such as custom macros, error reporting, or `trust` mode for user-supplied HTML.
```ts
const rehypePlugins: RehypePlugins = [
[rehypeKatex, { throwOnError: false, macros: { '\\RR': '\\mathbb{R}' } }],
];
```
Refer to the `remark-math` and `rehype-katex` documentation for additional capabilities like equation numbering or custom renderers.
---
---
url: /guide/streaming-markdown.md
---
# Streaming Markdown
Markdown generated by an LLM is often temporarily invalid while the response is still streaming. A fenced code block may be missing its closing backticks, a list may be half-written, or a plugin may reject an intermediate state.
VueMarkik is designed to handle that pattern without forcing the UI to flicker or flooding the console with warnings.
## Which Component to Use
All three rendering components support `error-mode` and preserve the last successful render by default when an updated render fails.
Choose between them based on how the rest of your app works:
* `Markdown`: use when your rendering path is synchronous and you want the simplest component
* `MarkdownAsync`: use when you already rely on Vue ``
* `MarkdownHooks`: use for reactive async updates, especially streamed LLM output
If you are consuming incremental model output directly, `MarkdownHooks` is usually the best default because it reacts naturally to changes in the `text` prop.
## Recommended Configuration
For LLM output, start with:
```vue
```
This configuration does two things:
* Preserves the last successful render when a streamed update is temporarily invalid
* Avoids console warnings by default
The same `error-mode` behavior is available on `Markdown` and `MarkdownAsync` as well:
```vue
```
## Error Modes
VueMarkik exposes three render error modes:
* `silent`: preserve the last successful render and emit `render-error`
* `warn`: preserve the last successful render, emit `render-error`, and log a warning
* `throw`: throw the render failure immediately
For production LLM output, `silent` is the right default. Use `warn` while debugging plugin behavior. Use `throw` in tests or when you want failures to stop rendering immediately.
## Timed Demo
The following example rotates through valid and broken snapshots automatically. Try switching error modes to compare how recovery behaves.
::: raw
:::
## What Happens on a Failed Update
When a streamed update cannot be rendered:
1. VueMarkik attempts to process the latest markdown snapshot.
2. If the render fails, the component emits `render-error`.
3. The UI keeps showing the previous successful render.
4. When a later update becomes valid again, the rendered output updates normally.
This avoids a bad user experience where content flashes between rendered output and an empty state while the model is still generating.
## Observability
If you want to track rendering problems without showing them in the console, listen to `render-error` and send the payload to your own logging or monitoring system.
```vue
```
## Related Guides
* [API Reference](./api-reference)
* [Remark & Rehype Plugins](./remark-rehype-plugins)
* [Syntax Highlighting](./syntax-highlighting)
---
---
url: /guide/api-reference.md
---
# API Reference
Complete reference for vuemarkik components, props, events, and slots.
## Components
### Markdown
Synchronous markdown renderer. Processes markdown immediately during component setup.
If a render fails, `Markdown` preserves the last successful render by default. This is useful when the markdown source is updated incrementally, for example while streaming output from an LLM.
**Props:**
| Prop | Type | Required | Default | Description |
| ---------------- | ----------------- | -------- | ----------------------- | ----------------------------------------- |
| `text` | `string` | Yes | - | Markdown content to render |
| `components` | `object` | No | `{}` | Custom Vue components for HTML elements |
| `remarkPlugins` | `RemarkPlugins` | No | `[]` | Remark plugins to process markdown |
| `rehypePlugins` | `RehypePlugins` | No | `[]` | Rehype plugins to transform HTML |
| `securityMode` | `SecurityMode` | No | `'safe'` | Selects safe or trusted plugin output |
| `sanitizeSchema` | `SanitizeSchema` | No | `defaultSanitizeSchema` | Configures final-HAST sanitization |
| `urlTransform` | `UrlTransform` | No | `defaultUrlTransform` | Filters or rewrites URL properties |
| `errorMode` | `RenderErrorMode` | No | `'silent'` | Controls how render failures are surfaced |
**Events:**
| Event | Payload | Description |
| -------------- | -------------------- | -------------------------------------------------------------------- |
| `render-error` | `RenderErrorPayload` | Emitted when markdown rendering fails in `'silent'` or `'warn'` mode |
**Slots:**
All HTML element names (e.g., `h1`, `p`, `code`, `a`) can be used as slots. Each slot receives `childMarkdown` plus the normal props for that element, such as `href` on links.
**Usage:**
```vue twoslash
```
**With Custom Components:**
```vue twoslash
```
***
### MarkdownAsync
Asynchronous markdown renderer. Uses async setup for processing markdown. Requires wrapping in ``. Use this when using rehype or remark plugins that need to run asynchronously.
If an updated render fails, `MarkdownAsync` keeps the previous successful output unless `errorMode` is set to `'throw'`.
**Props:**
| Prop | Type | Required | Default | Description |
| ---------------- | ----------------- | -------- | ----------------------- | ----------------------------------------- |
| `text` | `string` | Yes | - | Markdown content to render |
| `components` | `object` | No | `{}` | Custom Vue components for HTML elements |
| `remarkPlugins` | `RemarkPlugins` | No | `[]` | Remark plugins to process markdown |
| `rehypePlugins` | `RehypePlugins` | No | `[]` | Rehype plugins to transform HTML |
| `securityMode` | `SecurityMode` | No | `'safe'` | Selects safe or trusted plugin output |
| `sanitizeSchema` | `SanitizeSchema` | No | `defaultSanitizeSchema` | Configures final-HAST sanitization |
| `urlTransform` | `UrlTransform` | No | `defaultUrlTransform` | Filters or rewrites URL properties |
| `errorMode` | `RenderErrorMode` | No | `'silent'` | Controls how render failures are surfaced |
**Events:**
| Event | Payload | Description |
| -------------- | -------------------- | -------------------------------------------------------------------- |
| `render-error` | `RenderErrorPayload` | Emitted when markdown rendering fails in `'silent'` or `'warn'` mode |
**Slots:**
All HTML element names can be used as slots. Each slot receives `childMarkdown` plus the normal props for that element, such as `href` on links.
**Usage:**
```vue twoslash
```
**Note:** `MarkdownAsync` is ideal when using plugins with async operations or when you need non-blocking rendering.
***
### MarkdownHooks
Reactive markdown renderer using Vue composables. Provides reactive updates and emits events. Use this when using rehype or remark plugins that run asynchronously.
`MarkdownHooks` is the best fit for LLM-style streaming updates. When an intermediate update fails to render, the component preserves the last successful output and waits for the next valid update.
**Props:**
| Prop | Type | Required | Default | Description |
| ---------------- | ----------------- | -------- | ----------------------- | ----------------------------------------- |
| `text` | `string` | Yes | - | Markdown content to render |
| `components` | `object` | No | `{}` | Custom Vue components for HTML elements |
| `remarkPlugins` | `RemarkPlugins` | No | `[]` | Remark plugins to process markdown |
| `rehypePlugins` | `RehypePlugins` | No | `[]` | Rehype plugins to transform HTML |
| `securityMode` | `SecurityMode` | No | `'safe'` | Selects safe or trusted plugin output |
| `sanitizeSchema` | `SanitizeSchema` | No | `defaultSanitizeSchema` | Configures final-HAST sanitization |
| `urlTransform` | `UrlTransform` | No | `defaultUrlTransform` | Filters or rewrites URL properties |
| `errorMode` | `RenderErrorMode` | No | `'silent'` | Controls how render failures are surfaced |
**Events:**
| Event | Payload | Description |
| ---------------- | -------------------- | -------------------------------------------------------------------- |
| `content-loaded` | None | Emitted when markdown processing completes successfully |
| `render-error` | `RenderErrorPayload` | Emitted when markdown rendering fails in `'silent'` or `'warn'` mode |
**Slots:**
All HTML element names can be used as slots. Each slot receives `childMarkdown` plus the normal props for that element, such as `href` on links.
**Usage:**
```vue
```
**Note:** `MarkdownHooks` uses reactive async rendering to update content as the `text` prop changes.
**LLM Streaming Example:**
```vue
```
***
### MarkdownChildNodes
Utility component for rendering child nodes within custom slots.
**Props:**
| Prop | Type | Required | Default | Description |
| ------ | -------- | -------- | ------- | ------------------------------------------- |
| `node` | `object` | Yes | - | Object containing the `childMarkdown` VNode |
**Usage:**
```vue twoslash
```
***
## Props Reference
### Common Props
All markdown rendering components (`Markdown`, `MarkdownAsync`, `MarkdownHooks`) share the same props:
#### text
* **Type:** `string`
* **Required:** Yes
* **Description:** The markdown content to render
```ts twoslash
import { Markdown } from 'vuemarkik';
// ---cut---
const markdown: string = '# Hello\n\nThis is markdown.';
```
#### components
* **Type:** `Partial`
* **Required:** No
* **Default:** `{}`
* **Description:** Object mapping HTML element names to custom Vue components
If you provide both `components` and a same-named slot for the same tag, the slot takes precedence.
```ts twoslash
import { Markdown } from 'vuemarkik';
import { defineComponent } from 'vue';
// ---cut---
const CustomLink = defineComponent({
template: '',
});
const components = {
a: CustomLink,
code: defineComponent({ template: '' }),
};
```
#### remarkPlugins
* **Type:** `RemarkPlugins`
* **Required:** No
* **Default:** `[]`
* **Description:** Array of remark plugins to process markdown AST
```ts twoslash
import type { RemarkPlugins } from 'vuemarkik';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
// ---cut---
const plugins: RemarkPlugins = [remarkGfm, remarkMath];
```
#### rehypePlugins
* **Type:** `RehypePlugins`
* **Required:** No
* **Default:** `[]`
* **Description:** Array of rehype plugins to transform HTML AST
```ts twoslash
import type { RehypePlugins } from 'vuemarkik';
import rehypeKatex from 'rehype-katex';
import rehypeMermaid from 'rehype-mermaid';
// ---cut---
const plugins: RehypePlugins = [rehypeKatex, rehypeMermaid];
```
#### securityMode
* **Type:** `'safe' | 'trusted'`
* **Required:** No
* **Default:** `'safe'`
* **Description:** Controls whether final HAST is sanitized after plugins run
Safe mode owns the final sanitization boundary. Trusted mode preserves legacy
plugin output and should only be used with trusted markdown and plugins.
```ts twoslash
import type { SecurityMode } from 'vuemarkik';
// ---cut---
const securityMode: SecurityMode = 'safe';
```
#### sanitizeSchema
* **Type:** `SanitizeSchema`
* **Required:** No
* **Default:** `defaultSanitizeSchema`
* **Description:** Configures the allowlist used by final-HAST sanitization
The prop is only used in safe mode. Extend the exported default rather than
starting from an empty object:
```ts twoslash
import { defaultSanitizeSchema, type SanitizeSchema } from 'vuemarkik';
// ---cut---
const sanitizeSchema: SanitizeSchema = {
...defaultSanitizeSchema,
attributes: {
...defaultSanitizeSchema.attributes,
code: [
...(defaultSanitizeSchema.attributes?.code ?? []),
['className', 'language-javascript'],
],
},
};
```
Custom schemas change the security boundary. See [Security](./security).
#### urlTransform
* **Type:** `UrlTransform`
* **Required:** No
* **Default:** `defaultUrlTransform`
* **Description:** Filters or rewrites URL-bearing HAST properties after
plugins run
The default allows relative, fragment, query, HTTP, HTTPS, email, and telephone
URLs. It removes properties that use other explicit protocols. Return
`undefined` from a custom transform to remove a property.
```ts twoslash
import { defaultUrlTransform, type UrlTransform } from 'vuemarkik';
// ---cut---
const urlTransform: UrlTransform = (url) => {
const safeUrl = defaultUrlTransform(url);
return safeUrl?.replace('https://old.example/', 'https://new.example/');
};
```
See [Security](./security) before replacing the default policy.
#### errorMode
* **Type:** `'silent' | 'warn' | 'throw'`
* **Required:** No
* **Default:** `'silent'`
* **Description:** Controls how rendering failures are surfaced
Use `'silent'` when rendering markdown that may be temporarily invalid, such as streamed LLM output. The component keeps the last successful render and emits `render-error` without writing to the console.
Use `'warn'` while debugging to log a warning for each failed render. Use `'throw'` when you want failures to surface immediately, for example in tests.
```ts twoslash
import type { RenderErrorMode } from 'vuemarkik';
// ---cut---
const errorMode: RenderErrorMode = 'silent';
```
### Common Events
#### render-error
* **Payload:** `RenderErrorPayload`
* **Description:** Fired when a markdown render attempt fails in `'silent'` or `'warn'` mode. In `'throw'` mode the error is rethrown instead.
```ts twoslash
import type { RenderErrorPayload } from 'vuemarkik';
// ---cut---
function onRenderError(payload: RenderErrorPayload) {
console.debug(payload.error, payload.text);
}
```
### MarkdownHooks Events
#### content-loaded
* **Payload:** None
* **Description:** Fired after `MarkdownHooks` completes a successful async render
## Slots Reference
### Dynamic Slots
VueMarkik components support dynamic slots for any HTML element. The slot name corresponds to the HTML tag name.
**Available Slot Names:**
Any valid HTML element name can be used as a slot:
* Headings: `h1`, `h2`, `h3`, `h4`, `h5`, `h6`
* Text: `p`, `span`, `strong`, `em`, `code`
* Lists: `ul`, `ol`, `li`
* Links: `a`
* Structure: `div`, `section`, `article`
* And many more...
**Slot Props:**
Each slot receives a props object. `childMarkdown` is always present, and element-specific props are passed through as well:
```ts twoslash
import { VNode } from 'vue';
// ---cut---
type SlotProps = {
childMarkdown: VNode;
[propName: string]: unknown;
};
```
**Example:**
```vue twoslash
```
***
## Component Selection Guide
Choose the right component for your use case:
| Component | Use When |
| ---------------------- | ----------------------------------------------------------- |
| **Markdown** | Default choice for most cases. Fast, synchronous rendering. |
| **MarkdownAsync** | Using plugins with async operations. Requires ``. |
| **MarkdownHooks** | Async plugins, reactive updates, or streamed LLM output. |
| **MarkdownChildNodes** | Rendering children in custom slots. Not used standalone. |
::: tip Recommendation
If you are not using asynchronous plugins use with `Markdown`. If you need async support `MarkdownHooks` is recommended unless you are already using `Suspense` in your applications.
:::
::: tip Streaming Markdown
For LLM-generated markdown, prefer `MarkdownHooks` with `error-mode="silent"`. If an intermediate chunk is temporarily invalid, VueMarkik keeps the last successful render and emits `render-error` so you can observe failures without flooding the console.
:::
See also: [Streaming Markdown](./streaming-markdown)
---
---
url: /api-examples.md
---
# Runtime API Examples
This page demonstrates usage of some of the runtime APIs provided by VitePress.
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
```md
## Results
### Theme Data
{{ theme }}
### Page Data
{{ page }}
### Page Frontmatter
{{ frontmatter }}
```
## Results
### Theme Data
### Page Data
### Page Frontmatter
## More
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).