def deps do
[{:mdex, "~> 0.11"}]
end
$ mix igniter.install mdex
## See It In Action
Markdown in. Everything out.
# Welcome to **MDEx**
Features:
- Fast
- Extensible
- Phoenix-ready
```elixir
MDEx.to_html!("# Hello")
```
<h1>Welcome to <strong>MDEx</strong></h1>
<p>Features:</p>
<ul>
<li>Fast</li>
<li>Extensible</li>
<li>Phoenix-ready</li>
</ul>
<pre class="athl" style="...">
<code class="language-elixir">
<div class="line" data-line="1"><span style="...">
MDEx.to_html!("# Hello")
</span></div>
</code>
</pre>
#MDEx.Document<17 nodes
├── 1 [heading] level: 1
│ ├── 2 [text] literal: "Welcome to "
│ └── 3 [strong]
│ └── 4 [text] literal: "MDEx"
├── 5 [paragraph]
│ └── 6 [text] literal: "Features:"
├── 7 [list] list_type: :bullet, tight: true
│ ├── 8 [list_item]
│ │ └── 9 [paragraph]
│ │ └── 10 [text] literal: "Fast"
│ ├── 11 [list_item]
│ │ └── 12 [paragraph]
│ │ └── 13 [text] literal: "Extensible"
│ └── 14 [list_item]
│ └── 15 [paragraph]
│ └── 16 [text] literal: "Phoenix-ready"
└── 17 [code_block] info: "elixir", fenced: true
>
%Phoenix.LiveView.Rendered{
static: ["<h1>Welcome to <strong>MDEx</strong></h1>\n..."],
dynamic: #Function<42.81571850/1 in :erl_eval.expr/6>,
fingerprint: 52776307825337990075203022359966918684,
root: false,
caller: :not_available
}
{
"type": "document",
"children": [
{
"type": "heading",
"level": 1,
"children": [...]
},
{
"type": "list",
"list_type": "bullet",
...
}
]
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document SYSTEM "CommonMark.dtd">
<document xmlns="http://commonmark.org/xml/1.0">
<heading level="1">
<text xml:space="preserve">Welcome to </text>
<strong>
<text xml:space="preserve">MDEx</text>
</strong>
</heading>
<paragraph>
<text xml:space="preserve">Features:</text>
</paragraph>
<list type="bullet" tight="true">
<item><paragraph><text>Fast</text></paragraph></item>
<item><paragraph><text>Extensible</text></paragraph></item>
<item><paragraph><text>Phoenix-ready</text></paragraph></item>
</list>
<code_block info="elixir">MDEx.to_html!("# Hello")</code_block>
</document>
[
%{"insert" => "Welcome to "},
%{"attributes" => %{"bold" => true}, "insert" => "MDEx"},
%{"attributes" => %{"header" => 1}, "insert" => "\n"},
%{"insert" => "Features:\n"},
%{"insert" => "Fast"},
%{"attributes" => %{"list" => "bullet"}, "insert" => "\n"},
%{"insert" => "Extensible"},
%{"attributes" => %{"list" => "bullet"}, "insert" => "\n"},
%{"insert" => "Phoenix-ready"},
%{"attributes" => %{"list" => "bullet"}, "insert" => "\n"},
...
]
## Blazingly Fast
Light on memory. Heavy on throughput.
## Features
{*} Phoenix HEEx Integration
docs →Native rendering to Phoenix.LiveView.Rendered for LiveView integration.
~MD[# {@title}]HEEX
[#] Syntax Highlighting
docs →100+ themes and 70+ languages powered by Tree-sitter and Neovim. Code blocks look beautiful out of the box.
>> autumnus.dev</> Document Manipulation
docs →Full AST with Enumerable, Collectable, and Access protocols. Parse, traverse, and transform.
MDEx.Document
[+] Plugin System
docs →Extend functionality with custom plugins. Process documents at any stage of the pipeline.
GFM, Mermaid, KaTeX
>>> AI Streaming Support
docs →Process incomplete markdown fragments progressively. Perfect for ChatGPT-style interfaces.
streaming: true
<-> Multiple Output Formats
docs →Output to HTML, HEEx, JSON, XML, Quill Delta, and Markdown. One parser, many outputs.
to_{html,json,xml,delta,markdown}
[!] Safety & Sanitization
docs →Built-in XSS protection with configurable sanitization. Safely render untrusted markdown content.
MDEx.Document.default_sanitize_options()
``` Code Block Decorators
docs →Override themes, highlight lines, and add CSS classes to code blocks with inline attributes.
```js theme=nord highlight_lines="2-3"
:) Emoji Built-in
docs →Shortcode support for emoji conversion. Write :rocket: and get the actual 🚀 emoji.
shortcodes: true
## Phoenix LiveView Ready
Write markdown with HEEx components. Render directly to LiveView.
def render(assigns) do
~MD"""
# Welcome, {@user.name}!
<.button phx-click="upgrade">
Upgrade to Pro
</.button>
Your plan: **{@plan}**
"""HEEX
end
Welcome, John!
Your plan: Free
## Built for AI Applications
Stream incomplete markdown fragments as they arrive. Perfect for ChatGPT-style interfaces.
>> Write a poem about Elixir
MDEx.new(streaming: true)
|> MDEx.Document.put_markdown("**The Rust")
|> MDEx.to_html!()
# => "<p><strong>The Rust</strong></p>"
| Feature | MDEx | Earmark | md | cmark |
|---|---|---|---|---|
| Active | [x] | [x] | [x] | [ ] |
| Pure Elixir | [ ] | [x] | [x] | [ ] |
| Extensible | [x] | [x] | [x] | [ ] |
| Syntax Highlighting | [x] | [ ] | [ ] | [ ] |
| Code Block Decorators | [x] | [ ] | [ ] | [ ] |
| Streaming (fragments) | [x] | [ ] | [ ] | [ ] |
| Phoenix HEEx components | [x] | [ ] | [ ] | [ ] |
| AST | [x] | [x] | [x] | [ ] |
| AST to Markdown | [x] | [~]2 | [ ] | [ ] |
| To HTML | [x] | [x] | [x] | [x] |
| To JSON | [x] | [ ] | [ ] | [ ] |
| To XML | [x] | [ ] | [ ] | [x] |
| To Manpage | [ ] | [ ] | [ ] | [x] |
| To LaTeX | [ ] | [ ] | [ ] | [x] |
| To Quill Delta | [x] | [ ] | [ ] | [ ] |
| Emoji | [x] | [ ] | [ ] | [ ] |
| GFM3 | [x] | [x] | [ ] | [ ] |
| GLFM4 | [x] | [ ] | [ ] | [ ] |
| Discord5 | [~]1 | [ ] | [ ] | [ ] |