Comark (Components in Markdown) parser: syntax, AST, Vue/React/Svelte/Angular renderers, plugins, and LLM streaming with auto-close.
A high-performance markdown parser with Comark (Components in Markdown) support, built on markdown-it, offering both string-based and streaming APIs.
Comark extends standard markdown with a powerful component system while maintaining full compatibility with CommonMark and GitHub Flavored Markdown. It provides:
comarknpm install comark or pnpm add comarkcomark@comark/vue@comark/react@comark/svelte@comark/angular@comark/html@comark/ansi@comark/nuxtimport { parseMarkdown } from 'comark'
const content = `---
title: Hello World
---
# Hello World
This is **markdown** with :icon component.
::alert{type="info"}
Important message
::
`
const result = await parseMarkdown(content)
console.log(result.nodes) // Markdown AST
console.log(result.frontmatter) // { title: 'Hello World' }
console.log(result.meta) // Additional metadata<template>
<Markdown :value="content" />
</template>
<script setup lang="ts">
import { Markdown } from '@comark/vue'
const content = `# Hello World`
</script>import { Markdown } from '@comark/react'
export default function App() {
return <Markdown value={content} />
}<script lang="ts">
import { Markdown } from '@comark/svelte'
const content = `# Hello World`
</script>
<Markdown value={content} />import { Component } from '@angular/core'
import { Markdown } from '@comark/angular'
@Component({
selector: 'app-root',
standalone: true,
imports: [Markdown],
template: `<comark-markdown [value]="content" />`,
})
export class AppComponent {
content = `# Hello World`
}This guide is organized into focused sections covering different aspects of the package:
Learn how to write Comark documents with complete syntax reference:
::component), inline components (:component), properties, slots, nesting{...} syntax[x] and [ ] syntax→ Read Full Markdown Syntax Guide
Complete guide for parsing and working with MarkdownDocument:
parseMarkdown() function with options (autoUnwrap, autoClose)parseMarkdown() with Shiki syntax highlightingMarkdownDocument with compact array-based nodesrenderHtmlFromDocument via @comark/html) or markdown (renderMarkdown via comark/render)→ Read Full Parsing & Document Model Guide
Comprehensive guide for rendering in Vue applications:
Markdown component setupcomponentsManifest for lazy-loaded components#slot-name syntax__node and parsed properties→ Read Full Vue Rendering Guide
Comprehensive guide for rendering in React applications:
Markdown component setupcomponentsManifest for lazy-loaded componentsclass → className, etc.)__node→ Read Full React Rendering Guide
Comprehensive guide for rendering in Svelte 5 applications:
Markdown component setup with $statecomponentsManifest for lazy-loaded components$stateMarkdownAsync with <svelte:boundary>Prose prefix for overriding native HTML elements→ Read Full Svelte Rendering Guide
Comprehensive guide for rendering in Angular 17+ applications:
Markdown standalone component setupProse{PascalTag}, PascalTag, tag priority order<ng-content select="[slot=name]">:binding resolution with ambient data inputdefineMarkdownComponent and defineMarkdownDocumentComponent→ Read Full Angular Rendering Guide
Guide for integrating Comark in AI agent and LLM streaming workflows:
Comark extends markdown with custom components while preserving readability:
<!-- Block Component -->
::alert{type="warning" .important}
This is a **warning** message with markdown support.
::
<!-- Inline Component -->
Check out this :icon-star{.text-yellow} component.
<!-- Component with Slots -->
::card
#header
## Title
#content
Main content
#footer
Footer
::Lightweight array-based structure for efficient processing:
interface MarkdownDocument {
nodes: [
["h1", { "id": "hello" }, "Hello"],
["p", {}, "Text with ", ["strong", {}, "bold"], " word"],
["alert", { "type": "info" }, "Message"]
],
frontmatter: {},
meta: {}
}import { parseMarkdown } from 'comark'
import { renderHtmlFromDocument } from '@comark/html'
import shiki from '@comark/html/plugins/shiki'
async function processMarkdownFile(filePath: string) {
const content = await readFile(filePath, 'utf-8')
const doc = await parseMarkdown(content, {
plugins: [
shiki({
themes: { light: 'github-dark', dark: 'github-dark' },
}),
],
})
return {
html: await renderHtmlFromDocument(doc),
frontmatter: doc.frontmatter,
toc: doc.meta.toc
}
}import { useState } from 'react'
import { Markdown } from '@comark/react'
export default function Editor() {
const [content, setContent] = useState('# Hello')
return (
<div className="split-editor">
<textarea value={content} onChange={e => setContent(e.target.value)} />
<Markdown value={content} />
</div>
)
}import { readFile } from 'node:fs/promises'
import { parseMarkdown } from 'comark'
async function processMultipleFiles(files: string[]) {
const results = await Promise.all(
files.map(async (file) => {
const content = await readFile(file, 'utf-8')
return await parseMarkdown(content)
})
)
results.forEach((result, i) => {
console.log(`File ${files[i]}:`)
console.log(` - ${result.nodes.length} nodes`)
})
}<template>
<article class="prose">
<Markdown :value="markdownContent" :components="docComponents" />
</article>
</template>
<script setup lang="ts">
import { Markdown } from '@comark/vue'
import { docComponents } from './components'
</script>comark)// Asynchronous parsing
parseMarkdown(source: string, options?: ParserOptions): Promise<MarkdownDocument>
// Auto-close unclosed syntax
autoCloseMarkdown(source: string): string@comark/html)// Render markdown to HTML string (parse + render in one step)
renderHtml(markdown: string, options?: ParserOptions & RendererOptions): Promise<string>
// Render a pre-parsed document to HTML
renderHtmlFromDocument(document: MarkdownDocument, options?: RendererOptions): Promise<string>
// Create a reusable render function with shared parser instance
createHtmlRenderer(options?: ParserOptions & RendererOptions): (markdown: string) => Promise<string>@comark/vue)<Markdown :value="markdownString" :components="customComponents" />@comark/react)<Markdown value={markdownString} components={customComponents} />@comark/svelte)<Markdown value={markdownString} components={customComponents} />@comark/angular)<comark-markdown [value]="markdownString" [components]="customComponents" />Full TypeScript definitions included:
import type {
MarkdownDocument,
Node,
ParserOptions,
} from 'comark'┌─────────────────────────────────────────┐
│ Markdown Input (String) │
└────────────────┬────────────────────────┘
│
┌────────▼────────┐
│ Auto-close │ (Optional)
│ Unclosed │
│ Syntax │
└────────┬────────┘
│
┌────────▼────────┐
│ Parse │
│ Frontmatter │ (YAML)
└────────┬────────┘
│
┌────────▼────────┐
│ MarkdownIt │
│ + Plugins │ (Comark, Tasks)
└────────┬────────┘
│
┌────────▼────────┐
│ Token │
│ Processing │
└────────┬────────┘
│
┌────────▼────────┐
│ Comark │
│ AST │
└────────┬────────┘
│
┌────────▼────────┐
│ Auto-unwrap │ (Optional)
└────────┬────────┘
│
┌────────▼────────┐
│ Generate TOC │
└────────┬────────┘
│
┌────────▼────────┐
│ MarkdownDocument │
│ (nodes + data │
│ + meta) │
└────────┬────────┘
│
┌───────────┬──────┴──────┬───────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Vue │ │ React │ │ Svelte │ │ Angular │
│ Renderer│ │ Renderer│ │ Renderer│ │ Renderer│
└─────────┘ └─────────┘ └─────────┘ └─────────┘See the test specifications for examples of all supported syntax features.
Run tests:
pnpm testRun specific test:
pnpm test -- tests/parse.test.tsComark is a comprehensive solution for parsing and rendering markdown with component support. It excels at:
MarkdownDocument model with compact nodesChoose Comark when you need:
Next Steps:
46aaca0
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.