Comark vs react-markdown
TL;DR: react-markdown renders standard Markdown to React elements and lets you remap HTML tags to components. Comark does that too, and adds what react-markdown was never designed for: component syntax authors can write in the content itself, auto-close for token-by-token streaming, a serializable AST you can parse on the server, and renderers beyond React.
At a Glance
| Comark | react-markdown | |
|---|---|---|
| Runtime parsing | Yes | Yes |
Remap h1, a, code… to components | Yes, components map | Yes, components prop |
| Custom components in the content | Yes, ::alert{type="info"} | No, element remapping only |
| Streaming incomplete Markdown | Auto-close renders every frame correctly | Broken formatting until syntax completes |
| Frameworks | Vue, React, Svelte, Angular, Nuxt, HTML, ANSI | React only |
| Parse/render split | Decoupled, parse on server and render on client | Coupled, parsing happens inside the component |
| Underlying parser | markdown-exit (markdown-it compatible) | remark (unified) |
| Plugins | Comark plugins + markdown-it plugins | remark/rehype plugins |
| Frontmatter | Parsed out of the box | Needs remark-frontmatter + custom handling |
Element Mapping Works the Same Way
If you use react-markdown only to restyle elements, the model transfers directly:
import Markdown from 'react-markdown'
<Markdown
components={{
a: (props) => <Link {...props} />,
code: (props) => <CodeBlock {...props} />,
}}
>
{markdown}
</Markdown>import { Comark } from '@comark/react'
<Comark
components={{
a: Link,
code: CodeBlock,
}}
>
{markdown}
</Comark>What react-markdown Can't Express
react-markdown maps existing HTML elements to components. It has no syntax for components that aren't HTML elements: a callout, a tabbed code group, a video embed. The usual workaround is raw HTML plus rehype-raw, which reintroduces the verbosity and XSS surface Markdown was meant to avoid.
Comark makes components part of the syntax:
::alert{type="warning"}
This is **Markdown** inside a component, with full nesting support.
::
Status: :badge[Active]{color="green"}Writers, CMS editors, and LLMs can produce these components as plain text. No JSX, no HTML. See component syntax.
Streaming
react-markdown assumes a complete document. Feed it a stream mid-token and you get flashing asterisks, broken lists, and half-rendered code fences until the closing syntax arrives. This is the exact problem that led Vercel to build Streamdown.
Comark treats incomplete input as a first-class case. Auto-close completes unterminated syntax at every frame, and the streaming prop handles it end to end:
import { Comark } from '@comark/react'
import { useChat } from '@ai-sdk/react'
export function Message({ text, isStreaming }: { text: string, isStreaming: boolean }) {
return <Comark streaming={isStreaming}>{text}</Comark>
}Decoupled Parsing
react-markdown parses inside the React component, on every client that renders it. Comark separates the two: parse once (on the server, at build time, or in a worker) and render the compact AST anywhere:
import { parse } from 'comark'
const tree = await parse(markdown) // cache it, store it, send itimport { ComarkRenderer } from '@comark/react'
<ComarkRenderer tree={tree} components={{ Alert }} />The AST is plain arrays like ['h1', { id: 'hello' }, 'Hello'], cheap to serialize and cache. See the AST reference.
What react-markdown Does Well
- The unified ecosystem: hundreds of remark/rehype plugins. Comark's answer is its own plugin API plus compatibility with markdown-it plugins; check that your must-have plugins have an equivalent before switching.
- Maturity: react-markdown has been battle-tested for years across a huge install base.
If you render trusted, complete, standard Markdown in a React-only app and rely on specific remark plugins, react-markdown remains a solid choice.
FAQ
components mapping concept carries over. Swap the component first, then adopt ::component syntax where you need it.Comark vs MDX
Comark parses component syntax at runtime with no build step, while MDX compiles Markdown to JSX at build time. Compare syntax, architecture, framework support, and streaming.
Comark vs Streamdown
Streamdown streams Markdown in React. Comark streams Markdown with custom component syntax in Vue, React, Svelte, and Angular, with a decoupled parser and serializable AST.