Render Comark in Vue
The <Comark> component is the simplest way to render markdown in Vue. Pass markdown content directly and it handles parsing and rendering automatically.
Basic Usage
<script setup lang="ts">
import { Comark } from '@comark/vue'
import Alert from './Alert.vue'
const content = `# Hello World
This is **markdown** with Comark components.
::alert{type="info"}
This is an alert!
::
`
</script>
<template>
<Comark :components="{ Alert }">{{ content }}</Comark>
</template>
Props & Slots
| Prop | Type | Default | Description |
|---|---|---|---|
| (default slot) | string | - | Markdown content to parse and render |
markdown | string | undefined | Alternative to default slot - markdown content as prop |
options | ParseOptions | {} | Parser options (autoUnwrap, autoClose, etc.) |
plugins | ComarkPlugin[] | [] | Array of plugins (highlight, emoji, toc, etc.) |
components | Record<string, Component> | {} | Custom Vue component mappings |
componentsManifest | ComponentManifest | undefined | Dynamic component resolver function |
streaming | boolean | false | Enable streaming mode |
summary | boolean | false | Only render content before <!-- more --> |
caret | boolean | { class: string } | false | Append caret to last text node |
Using the markdown Prop
Instead of using the default slot, you can pass markdown content via the markdown prop:
<script setup lang="ts">
import { Comark } from '@comark/vue'
const content = '# Hello\n\nThis is **markdown**.'
</script>
<template>
<Comark :markdown="content" />
</template>
With Parser Options
Use the options prop to configure parser behavior:
<script setup lang="ts">
import { Comark } from '@comark/vue'
const content = '# Hello World'
const options = {
autoUnwrap: true, // Remove <p> wrappers from single-paragraph containers
autoClose: true // Auto-close incomplete syntax
}
</script>
<template>
<Comark :options="options">{{ content }}</Comark>
</template>
With Plugins
Use the plugins prop to add functionality like syntax highlighting, emoji support, or table of contents:
<script setup lang="ts">
import { Comark } from '@comark/vue'
import highlight from '@comark/vue/plugins/highlight'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
const content = `
\`\`\`javascript
console.log("Hello, World!")
\`\`\`
`
const plugins = [
highlight({
themes: {
light: githubLight,
dark: githubDark
}
})
]
</script>
<template>
<Suspense>
<Comark :plugins="plugins">{{ content }}</Comark>
</Suspense>
</template>
highlight) make <Comark> an async component. Wrap it in <Suspense> when using these plugins, or rendering will fail silently.With Custom Components
<script setup lang="ts">
import { Comark } from '@comark/vue'
import CustomAlert from './components/Alert.vue'
import CustomCard from './components/Card.vue'
const components = {
alert: CustomAlert,
card: CustomCard,
}
const content = `
::alert{type="warning"}
Important message here
::
::card{title="My Card"}
Card content
::
`
</script>
<template>
<Comark :components="components">{{ content }}</Comark>
</template>
Live Editor Example
<script setup lang="ts">
import { ref } from 'vue'
import { Comark } from '@comark/vue'
const content = ref('# Edit me!\n\nType **markdown** here.')
</script>
<template>
<div class="editor">
<textarea v-model="content" />
<div class="preview">
<Comark>{{ content }}</Comark>
</div>
</div>
</template>
Summary Mode
Render only content before <!-- more -->:
<script setup lang="ts">
import { Comark } from '@comark/vue'
const content = `# Article Title
This is the summary shown in listings.
<!-- more -->
This is the full article content.
`
</script>
<template>
<!-- Only renders "This is the summary shown in listings." -->
<Comark summary>{{ content }}</Comark>
</template>
Define Comark Component
The defineComarkComponent helper creates a pre-configured Comark component with default options, plugins, and components. This is useful for creating custom Comark components that can be reused throughout your application with consistent configuration.
Basic Usage
import { defineComarkComponent } from '@comark/vue'
// Create a custom Comark component with default configuration
export const MyComark = defineComarkComponent({
name: 'MyComark',
})
With Plugins
import { defineComarkComponent } from '@comark/vue'
import math from '@comark/vue/plugins/math'
import mermaid from '@comark/vue/plugins/mermaid'
export const DocsComark = defineComarkComponent({
name: 'DocsComark',
plugins: [
math(),
mermaid(),
],
})
With Custom Components
import { defineComarkComponent } from '@comark/vue'
import { Math } from '@comark/vue/plugins/math'
import { Mermaid } from '@comark/vue/plugins/mermaid'
import CustomAlert from './components/CustomAlert.vue'
import CustomCard from './components/CustomCard.vue'
export const AppComark = defineComarkComponent({
name: 'AppComark',
components: {
Math,
Mermaid,
alert: CustomAlert,
card: CustomCard,
},
})
With Syntax Highlighting
import { defineComarkComponent } from '@comark/vue'
import highlight from '@comark/vue/plugins/highlight'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
export const CodeComark = defineComarkComponent({
name: 'CodeComark',
plugins: [
highlight({
themes: {
light: githubLight,
dark: githubDark,
},
}),
],
})
Complete Configuration Example
import { defineComarkComponent } from '@comark/vue'
import math from '@comark/vue/plugins/math'
import mermaid from '@comark/vue/plugins/mermaid'
import highlight from '@comark/vue/plugins/highlight'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
import { Math } from '@comark/vue/plugins/math'
import { Mermaid } from '@comark/vue/plugins/mermaid'
import CustomAlert from './components/CustomAlert.vue'
export const AppComark = defineComarkComponent({
name: 'AppComark',
// Plugins
plugins: [
math(),
mermaid(),
highlight({
themes: {
light: githubLight,
dark: githubDark,
},
}),
],
// Custom components
components: {
Math,
Mermaid,
alert: CustomAlert,
},
})
Using the Defined Component
Once defined, use it like the standard <Comark> component:
<script setup lang="ts">
import { AppComark } from './comark'
const content = `
# Math Example
Inline math: $E = mc^2$
$$
\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}
$$
::alert{type="info"}
This uses pre-configured components and plugins!
::
`
</script>
<template>
<!-- All configuration is already included -->
<AppComark>{{ content }}</AppComark>
<!-- Can still override per-instance -->
<AppComark :components="{ alert: DifferentAlert }">{{ content }}</AppComark>
</template>
Configuration Options
interface DefineComarkComponentOptions {
// Component name (for Vue DevTools)
name?: string
// Parser options
autoUnwrap?: boolean
autoClose?: boolean
// Plugins
plugins?: ComarkPlugin[]
// Custom components
components?: Record<string, any>
}
Benefits
- Centralized Configuration: Define options once, use everywhere
- Consistent Behavior: Same plugins and components across your app
- Type Safety: Full TypeScript support
- Easy Overrides: Instance-level props can override defaults
- Better DevTools: Named components appear in Vue DevTools
Merging Behavior
When using the defined component, configurations are merged:
<script setup lang="ts">
import { AppComark } from './comark'
import SpecialAlert from './SpecialAlert.vue'
import emoji from '@comark/vue/plugins/emoji'
</script>
<template>
<AppComark
:plugins="[emoji()]"
:components="{ alert: SpecialAlert }"
>
{{ content }}
</AppComark>
</template>
Merge rules:
plugins: Arrays are concatenated (config plugins + prop plugins)components: Props override config (prop components take precedence)- Other
options: Props override config
Real-World Example
import { defineComarkComponent } from '@comark/vue'
import math, { Math } from '@comark/vue/plugins/math'
import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid'
import highlight from '@comark/vue/plugins/highlight'
import githubLight from '@shikijs/themes/github-light'
import githubDark from '@shikijs/themes/github-dark'
import ProsePre from './components/ProsePre.vue'
import ProseAlert from './components/ProseAlert.vue'
export const DocsComark = defineComarkComponent({
name: 'DocsComark',
plugins: [
math(),
mermaid(),
highlight({
themes: {
light: githubLight,
dark: githubDark,
},
}),
],
components: {
Math,
Mermaid,
ProsePre,
alert: ProseAlert,
},
autoUnwrap: true,
autoClose: true,
})
<script setup lang="ts">
import { DocsComark } from '~/comark'
const { data: page } = await useFetch(`/api/docs/${route.params.slug}`)
</script>
<template>
<article class="prose">
<DocsComark>{{ page.content }}</DocsComark>
</article>
</template>
Custom Components
The <Comark> component supports custom components. Components receive props from the markdown and render children via slots.
Creating a Custom Alert
<script setup lang="ts">
defineProps<{
type?: 'info' | 'warning' | 'error' | 'success'
}>()
</script>
<template>
<div class="alert" :class="`alert-${type || 'info'}`" role="alert">
<slot />
</div>
</template>
<style scoped>
.alert { padding: 1rem; border-radius: 0.5rem; }
.alert-info { background: #e3f2fd; }
.alert-warning { background: #fff3e0; }
.alert-error { background: #ffebee; }
.alert-success { background: #e8f5e9; }
</style>
Usage in markdown:
::alert{type="warning"}
This is a warning message!
::
Component with Named Slots
<template>
<div class="card">
<div v-if="$slots.header" class="card-header">
<slot name="header" />
</div>
<div class="card-body">
<slot />
</div>
<div v-if="$slots.footer" class="card-footer">
<slot name="footer" />
</div>
</div>
</template>
Usage in markdown:
::card
#header
Card Title
#footer
Footer content
This is the card body.
::
Overriding HTML Elements
Override default element rendering:
<script setup lang="ts">
const props = defineProps<{
__node?: any
id?: string
}>()
</script>
<template>
<component :is="__node?.[0] || 'h2'" :id="id" class="heading">
<a v-if="id" :href="`#${id}`" class="anchor">#</a>
<slot />
</component>
</template>
<script setup lang="ts">
const components = {
h1: Heading,
h2: Heading,
h3: Heading,
}
</script>
<template>
<Comark :components="components">{{ content }}</Comark>
</template>
TypeScript Support
<script setup lang="ts">
import type { Component } from 'vue'
import { Comark } from '@comark/vue'
interface Props {
content: string
components?: Record<string, Component>
}
const props = defineProps<Props>()
</script>
<template>
<Comark :components="props.components">{{ props.content }}</Comark>
</template>
Next Steps
- Streaming - Real-time incremental parsing for AI chat
- HTML Rendering - Framework-free HTML/Markdown output
- React Rendering - React integration
- Components Syntax - Block and inline component syntax
- Parse API - Parsing options and error handling