Skip to content

Carve vs Markdown, Djot & MDX

This page compares syntax and implementation characteristics. For conversion instructions, see Coming from Markdown. For parser differences, see Differences from Djot.

The table is maintained by the Carve project. See Markup language comparison for AsciiDoc, reStructuredText, Textile, and other languages.

Legend

✅ native  ·  🧩 plugin / extension needed  ·  ⚠️ partial / convention  ·  ❌ not available

At a glance

Markdown (CommonMark)DjotMDXCarve
Published grammar⚠️ specification plus prose rules❌ (Markdown + JSX)✅ EBNF
Consistent inline rules
No-backtracking parse guarantee✅ *
Markdown-familiar syntax⚠️⚠️
Paragraph interruption (no blank line)✅ **

* Inline parsing is single-pass with a delimiter stack; at the block level a code or raw fence uses a bounded forward scan for a matching closer. A ::: container opens without that lookahead and may close at end of input. See Technical Rationale. ** Like Markdown for quotes, headings, tables and closed fences; list markers (both bullet and ordered) deliberately never interrupt a paragraph - a list needs a blank line (no CommonMark 1.-only heuristic).

Paragraph interruption, by rule count

Approximate number of rules that determine whether a new block can start without a preceding blank line. These are summaries for authors, not grammar production counts.

ModelInterruption rules
Markdown (CommonMark)~8–10, irregular - setext underline, ordered list only if it starts with 1, indented code can't interrupt, HTML-block type 7 can't, bullet only if the first item is non-empty, …
MDXinherits Markdown's (~8–10), plus JSX block handling
Djot1 - nothing interrupts; a blank line precedes every block
Carve3 - visible block-openers interrupt (heading, quote, table row, open fence, thematic break); list markers fold (never interrupt); fence / ::: closers and bare images don't interrupt

Carve uses three rule groups: block markers that start a new block, list markers that remain in the paragraph, and closing markers that do not start a block.

Authoring features

MarkdownDjotMDXCarve
Tables🧩 GFM🧩 GFM
Table rowspan / colspan
Captions on figures, tables, code, quotes🧩 Pandoc, images only⚠️ tables only🧩 component✅ one ^ line, every captionable block
A lone image is a block❌ wrapped in <p>❌ wrapped in <p>✅ bare <img>, so a caption has a host
Footnotes🧩🧩
Math🧩🧩
Definition lists🧩🧩
Admonitions / callouts🧩⚠️ via div🧩 component✅ native
Attributes {.class #id}🧩 (Pandoc, markdown-it-attrs)⚠️ JSX props
Generic divs / spans🧩 (Pandoc fenced divs / spans)⚠️ components
Smart typography🧩🧩
Editorial / critic markup
Frontmatter⚠️ tooling🧩
Symbols / emoji shortcodes🧩✅ symbols, mapped via filters🧩:name: symbols, mapped via config

Djot already spells a table caption ^ Caption. Carve keeps that spelling and lets it attach to any captionable block. The two rules work together: a lone image is a block rather than paragraph text, which is what gives the caption line something to attach to, and the pair renders as <figure> with a <figcaption>. Markdown and Djot wrap the same image in a paragraph, so the caption has to be written as raw HTML.

Docs & cross-referencing

MarkdownDjotMDXCarve
Automatic heading ids⚠️ tooling🧩✅ case-preserving, case-insensitive refs
Cross-references </#id>
Implicit heading refs [Heading][]🧩 (Obsidian uses [[…]])

Safety & ecosystem

MarkdownDjotMDXCarve
Built-in safety requirements❌ consumer's job❌ consumer's jobn/a✅ URL, attribute, Unicode, and resource protections
URL / attribute / DoS hardening by default✅ always on
Raw HTML default⚠️ on (libs vary)⚠️ onruns JS⚠️ on, one-flag opt-out / safe mode
Embeds live components / JS✅ (its purpose)❌ by design
Independent implementationsmany, divergentseveral (js, lua, rust, go)JS-onlyphp · js · rs, conformance-tested
Implementations share expected results⚠️⚠️

See Security → How Carve compares on security for the detailed breakdown and caveats.

When to pick which

  • Markdown: broad parser and platform support; advanced document features depend on the selected Markdown variant or plugins.
  • Djot: specified parsing rules, attributes, tables, and footnotes with a smaller implementation ecosystem.
  • MDX: Markdown combined with JavaScript components; suitable when document source is also application code.
  • Carve: built-in cross-references, captions, table spans, and multiple output formats, with separate JavaScript, PHP, and Rust implementations.

See Technical rationale for parsing decisions and Differences from Djot for syntax changes.

Released under the MIT License.