Convert Typst content to CommonMark strings.
Written entirely in Typst script — no external tooling required.
#import "@preview/to-commonmark:0.1.0": to-commonmark
#let doc = [
= Introduction
This is a _Typst_ document with *bold*, `code`, and lists:
- First
- Second
- Third
#quote(block: true)[A block quote with multiple paragraphs is easy.]
]
#let commonmark = to-commonmark(doc)The result is a plain CommonMark string:
# Introduction
This is a *Typst* document with **bold**, `code`, and lists:
- First
- Second
- Third
> A block quote with multiple paragraphs is easy.| Typst Element | CommonMark Output |
|---|---|
Headings (=, ==, …) |
# H1 through ###### H6 (clamped at 6) |
| Paragraphs | Separated by blank lines |
Unordered lists (- item) |
- item with 2-space indentation |
Ordered lists (+ item) |
1. item (code mode enum) |
Block quotes (#quote(block: true)) |
> text |
| Code blocks (fenced) | `` ``` with language info string |
| Inline code | `code` |
Strong (#strong) |
**text** |
Emphasis (#emph) |
*text* |
| Nested emphasis | Outer *, inner _ |
Links (#link) |
[text](url) or <url> (autolink) |
Images (#image) |
 |
| Line breaks | \n (trailing two spaces) |
Elements not in the table above emit an HTML comment:
<!-- dropped: equation -->
<!-- dropped: table -->Labels are silently dropped. Cross-references (@label) are
emitted as literal text (@label).
to-commonmark(content: content) -> str
Takes arbitrary Typst content and returns a CommonMark string.
The function accepts content produced by Typst markup, code-mode
constructors (list(), enum(), heading(), etc.), or any
combination thereof.
A single-pass recursive walk over the Typst content tree:
- Dispatch on element type via
elem.func() - Context-threaded mode —
"block"or"inline"— determines how sequences of children are joined (\n\nvs"") - Inline emphasis nesting —
emph-depthtracks nesting so the innermost emphasis uses_/__to avoid ambiguity - Sequence grouping — consecutive inline elements are merged
into paragraphs; consecutive
itemelements (from markup-mode lists) are grouped into bullet lists
- Ordered lists in markup mode (
+ item) are rendered as unordered (- item). Use code-modeenum()for ordered lists. - Image dimensions are silently dropped.
- Tables, math, figures, strikethrough, and footnotes emit drop comments rather than CommonMark equivalents.
- HTML pass-through (e.g. images with dimensions, table markup) is not supported.
Tested with Typst 0.14.x.