Rendering
Render to Markdown
Convert a Comark AST back to markdown, preserving frontmatter and component syntax.
The renderMarkdown function converts a ComarkTree back into a markdown string, preserving frontmatter, component syntax, and attributes. Use it for round-tripping (parse, transform, serialize), content migration, programmatic editing, or generating markdown from an AST.
renderMarkdown(tree, options?)
import { parse } from 'comark'import { renderMarkdown } from 'comark/render'const tree = await parse(`---title: Hello---# Hello **World**::alert{type="info"}This is an alert::`)const markdown = await renderMarkdown(tree)The output is a complete markdown document including the frontmatter block:
---title: Hello---# Hello **World**::alert{type="info"}This is an alert::Options
renderMarkdown accepts an optional RenderMarkdownOptions object:
| Option | Type | Default | Description |
|---|---|---|---|
maxInlineAttributes | number | 3 | Maximum attributes before switching to YAML block syntax. Set to 0 to always use block syntax |
components | Record<string, NodeHandler> | {} | Custom render handlers for specific elements |
data | Record<string, any> | {} | Additional data passed to render handlers |
Inline vs Block Attributes
When a component has more attributes than maxInlineAttributes, Comark switches to YAML block syntax:
// Renders as inline when 3 or fewer attributes// ::card{title="Hello" icon="star" color="blue"}// Switches to block syntax when more than 3// ::card// ---// title: Hello// icon: star// color: blue// size: large// ---const md = await renderMarkdown(tree, { maxInlineAttributes: 0 })// Always uses block syntax:// ::alert// ---// type: info// ---// Content here// ::Use Cases
Round-trip Transformation
Parse markdown, programmatically transform the AST, then serialize back:
import { parse } from 'comark'import { renderMarkdown } from 'comark/render'import { visit } from 'comark/utils'const tree = await parse(source)// Add an "external" class to all linksvisit(tree, (node) => Array.isArray(node) && node[0] === 'a', (node) => { const el = node as [string, Record<string, any>, ...any[]] if (el[1].href?.startsWith('http')) { el[1].target = '_blank' } })const output = await renderMarkdown(tree)Content Migration
Convert between attribute styles or normalize formatting:
import { parse } from 'comark'import { renderMarkdown } from 'comark/render'async function normalizeDocument(source: string) { const tree = await parse(source) // Re-serialize with consistent formatting return renderMarkdown(tree, { maxInlineAttributes: 0 })}Programmatic Document Generation
Build a Comark document from data:
import { renderMarkdown } from 'comark/render'import type { ComarkTree } from 'comark'const tree: ComarkTree = { frontmatter: { title: 'API Reference', date: '2025-01-01' }, meta: {}, nodes: [ ['h1', {}, 'API Reference'], ['p', {}, 'Welcome to the API docs.'], ['alert', { type: 'info' }, 'This API is in beta.'], ],}const markdown = await renderMarkdown(tree)See Also
- Parse API — Parse markdown into a
ComarkTree - HTML Rendering — Render to HTML strings
- Comark AST — AST format and node types
- API Reference — Full type reference