Cheat Sheet

Quick reference for all Comark exports, types, and APIs across all packages.

comark (core)

parseMarkdown(source, options?)

Parse Comark content into a MarkdownDocument.

import { parseMarkdown } from 'comark'
import shiki from 'comark/plugins/shiki'

const result = await parseMarkdown(source, {
  autoUnwrap: true,   // Remove <p> wrappers from single-paragraph containers
  autoClose: true,    // Auto-close incomplete syntax
  plugins: [shiki()]  // HTML parsing is on by default via the html plugin
})

result.nodes         // Node[]: parsed AST nodes
result.frontmatter   // Record<string, any>: frontmatter data
result.meta.toc      // TOC object (from toc plugin)
result.meta.summary  // Node[] (from summary plugin)

createMarkdownParser(options?)

Creates a reusable parser initialized once, more efficient for batch processing.

import { createMarkdownParser } from 'comark'

const parse = createMarkdownParser({ plugins: [shiki()] })

const tree1 = await parse('# Document 1')
const tree2 = await parse('# Document 2')

renderMarkdown(document, options?)

Convert a MarkdownDocument back to a markdown string.

import { parseMarkdown } from 'comark'
import { renderMarkdown } from 'comark/render'

const document = await parseMarkdown(source)
const markdown = await renderMarkdown(document, {
  maxInlineAttributes: 3,  // Switch to YAML block syntax above this threshold
})

autoCloseMarkdown(source)

Close unclosed markdown syntax and Comark components. Useful for streaming.

import { autoCloseMarkdown } from 'comark'

autoCloseMarkdown('**bold')        // '**bold**'
autoCloseMarkdown('::alert\nText') // '::alert\nText\n::'

String renderers

@comark/html

renderHtml(markdown, options?)

Parse and render markdown to an HTML string in one call.

import { renderHtml } from '@comark/html'

const html = await renderHtml('# Hello\n\nThis is **bold**.')

createHtmlRenderer(options?)

Creates a reusable parse+render function initialized once.

import { createHtmlRenderer } from '@comark/html'

const renderHtml = createHtmlRenderer({
  plugins: [shiki()],
  components: {
    alert: async ([, attrs, ...children], { render }) =>
      `<div class="alert-${attrs.type}">${await render(children)}</div>`
  }
})

const html = await renderHtml(source)

renderHtmlFromDocument(document, options?)

Render a pre-parsed MarkdownDocument to an HTML string.

import { renderHtmlFromDocument } from '@comark/html'

const html = await renderHtmlFromDocument(document, {
  components: {
    alert: async ([, attrs, ...children], { render }) =>
      `<div class="alert-${attrs.type}">${await render(children)}</div>`
  }
})

@comark/ansi

renderAnsi(markdown, options?)

Parse and render markdown to an ANSI-styled terminal string in one call.

import { renderAnsi } from '@comark/ansi'

const output = await renderAnsi('# Hello\n\nThis is **bold**.')
process.stdout.write(output)

createAnsiRenderer(options?)

Create a reusable parse-and-render function with pre-configured parser and ANSI renderer options.

import { createAnsiRenderer } from '@comark/ansi'

const renderAnsi = createAnsiRenderer({ colors: false, width: 120 })
const output = await renderAnsi('# Hello')

renderAnsiFromDocument(document, options?)

Render a pre-parsed MarkdownDocument to an ANSI-styled string.

import { parseMarkdown } from 'comark'
import { renderAnsiFromDocument } from '@comark/ansi'

const document = await parseMarkdown('# Hello')
const output = await renderAnsiFromDocument(document)
process.stdout.write(output)

printAnsi(markdown, options?)

Parse and render markdown directly to stdout. Replaces the deprecated writeAnsi alias.

import { printAnsi } from '@comark/ansi'

await printAnsi('# Hello\n\nThis is **bold**.')

createAnsiPrinter(options?)

Create a reusable Markdown printer. Pass writer to target something other than process.stdout. Replaces the deprecated createAnsiWriter alias.

import { createAnsiPrinter } from '@comark/ansi'

const printAnsi = createAnsiPrinter({
  writer: (output) => process.stderr.write(output),
})

await printAnsi('# Hello')

Framework renderers

@comark/vue · @comark/react · @comark/svelte · @comark/angular: same API, different import path.

<Markdown>

Parses and renders markdown in one async step.

<Markdown :plugins="[shiki()]" :components="{ alert: Alert }">
  {{ content }}
</Markdown>

<MarkdownDocument>

Renders a pre-parsed MarkdownDocument with no parser shipped to the client.

<MarkdownDocument :value="document" :components="{ alert: Alert }" />

defineMarkdownComponent(options)

Creates a pre-configured <Markdown> with baked-in plugins and component mappings.

import { defineMarkdownComponent } from '@comark/vue' // or @comark/react, @comark/angular

export const AppMarkdown = defineMarkdownComponent({
  plugins: [shiki(), toc()],
  components: { alert: CustomAlert },
})

Transforming nodes before render

transformNode lets you change the tag or props of an element node right before it renders, based on its props and the render context. Use it when a value is only known at render time, such as runtime data, and components alone can't express the change.

The option takes a function or an array of functions. Every renderer accepts it: the <Markdown> and <MarkdownDocument> components in Vue, React, Svelte, and Angular, defineMarkdownComponent, defineMarkdownDocumentComponent, and the @comark/html and @comark/ansi render functions.

import type { NodeTransform } from 'comark'

// Render every `::cta` as a link to the signed-in user's dashboard
const transformNode: NodeTransform = ({ tag, props, renderData }) => {
  if (tag !== 'cta') return
  return {
    tag: 'a',
    props: { ...props, href: `/users/${renderData.data.userId}/dashboard` },
  }
}
<MarkdownDocument :value="document" :data="{ userId: 42 }" :transform-node="transformNode" />

The function receives:

  • tag: the tag the renderer will use.
  • props: the node's attributes with : bindings resolved. Every renderer resolves them the same way: the : is removed, the value is parsed as JSON, and a value that isn't JSON is looked up as a data path. :count="5" gives { count: 5 }, and a path that doesn't exist gives undefined.
  • node: the node as it is in the document.
  • parent: the parent element node, when the renderer knows it. Svelte doesn't pass it.
  • renderData: { frontmatter, meta, data, props }, where props holds the parent's props.

Return { tag?, props? } to replace either one, or nothing to keep the node as it is. The returned props are final: : keys in them aren't resolved again. The node's children then see the returned props as their parent props, so :title="props.title" in a child reads the new value.

These rules apply:

  • Lookup: a returned tag is looked up like any tag, in components, then componentsManifest, then as a native element. An as prop still takes precedence in Vue, React, and Angular, so remove it from props if the new tag must win.
  • Order: with an array, each function sees the result of the previous one. defineMarkdownComponent and defineMarkdownDocumentComponent run their own transformNode before the instance's.
  • Safety: the returned tag and props are rendered as-is, like the output of a custom component. Comark doesn't sanitize them, and the security plugin runs at parse time, so its options don't apply either. You're responsible for validating anything the function builds from untrusted data, such as URLs from data, and for returning a valid tag name.
  • Purity: the function must be synchronous and must not mutate props, node, or renderData. It runs for every element node on every render, and Angular can call it twice for a node that renders as a custom component.
  • Stable reference: in Vue, React, and Angular, define the function or array once, outside the render. A new array on every render makes the document render again.

Types

MarkdownDocument

interface MarkdownDocument {
  nodes: Node[]
  frontmatter: Record<string, any>
  meta: {
    toc?: Toc
    summary?: Node[]
    [key: string]: any
  }
}

RenderMarkdownOptions

interface RenderMarkdownOptions {
  maxInlineAttributes?: number             // Max inline attributes before switching to YAML block (default: 3)
  blockAttributesStyle?: 'frontmatter' | 'codeblock'  // Block attribute syntax style (default: 'codeblock')
  rawHtmlText?: 'escape' | 'verbatim'      // Text inside raw HTML blocks: escape tag-like `<` (default) or keep as-is
  frontmatterOptions?: DumpOptions         // js-yaml options for frontmatter serialization
  components?: Record<string, NodeHandler | ConditionalNodeHandler> // Custom render handlers for specific elements
  data?: Record<string, any>              // Additional data passed to render handlers
}

Node

type Node =
  | string                                                        // TextNode
  | [tag: string, attrs: ElementNodeAttributes, ...children: Node[]]  // ElementNode
  | [tag: null, attrs: ElementNodeAttributes, comment: string]        // CommentNode

ParserOptions

interface ParserOptions {
  autoUnwrap?: boolean              // default: true
  autoClose?: boolean | AutoCloseFunction // default: true
  unwrap?: boolean | string | string[]  // strip top-level wrapper tags, e.g. 'p' (default: false)

  linkify?: boolean                 // deprecated: use registerDefaultPlugins: false + linkify()
  headingIds?: boolean | 'nested' | 'flat' // default: true ('flat') — slug from visible text; duplicates get -1, -2, … (keeps Unicode letters/numbers, omits symbol-only ids); explicit id wins
  registerDefaultPlugins?: boolean  // default: true
  plugins?: ComarkPlugin[]
  tracer?: ComarkTracer             // OpenTelemetry-style tracer for parse spans
}

Toc

// Exported from 'comark/plugins/toc'
interface Toc {
  title: string
  depth: number
  searchDepth: number
  links: TocLink[]
}

interface TocLink {
  id: string
  text: string
  depth: number
  children?: TocLink[]
}

Imports

imports.ts
// Core
import { parseMarkdown, createMarkdownParser, autoCloseMarkdown } from 'comark'
import { renderMarkdown } from 'comark/render'
import type { RenderMarkdownOptions } from 'comark/render'
import { defineComarkPlugin } from 'comark'

// Plugins
import shiki from 'comark/plugins/shiki'
import emoji from 'comark/plugins/emoji'
import toc from 'comark/plugins/toc'
import summary from 'comark/plugins/summary'
import security from 'comark/plugins/security'

// HTML rendering
import { createHtmlRenderer, renderHtml, renderHtmlFromDocument } from '@comark/html'

// ANSI rendering
import {
  renderAnsi,
  renderAnsiFromDocument,
  createAnsiRenderer,
  printAnsi,
  createAnsiPrinter,
} from '@comark/ansi'

// Vue
import { Markdown, MarkdownDocument, defineMarkdownComponent } from '@comark/vue'

// React
import { Markdown, MarkdownDocument, defineMarkdownComponent } from '@comark/react'

// Svelte
import { Markdown, MarkdownDocument } from '@comark/svelte'

// Types
import type {
  MarkdownDocument,
  ElementNode,
  TextNode,
  CommentNode,
  ElementNodeAttributes,
  Node,
  ParserOptions,
  ComarkPlugin,
} from 'comark'
Using Nuxt? Markdown and MarkdownDocument are auto-imported, no import statements needed.

© 2026 Vercel, Inc.