MDEx

MDEx logo

A fast 100% CommonMark-compatible GitHub Flavored Markdown parser and formatter for Elixir.

Hex VersionHex DocsMIT

Features

Check out some samples at https://mdex-c31.pages.dev

Installation

Add :mdex dependecy:

def deps do
  [
    {:mdex, "~> 0.1"}
  ]
end

Usage

Mix.install([{:mdex, "~> 0.1"}])
MDEx.to_html("# Hello")
#=> "<h1>Hello</h1>\n"

And you can change how the markdown is parsed and formatted by passing options to MDEx.to_html/2 to enable more features:

GitHub Flavored Markdown with emojis

MDEx.to_html(
  ~S"""
  # GitHub Flavored Markdown :rocket:

  - [x] Task A
  - [x] Task B
  - [ ] Task C

  | Feature | Status |
  | ------- | ------ |
  | Fast | :white_check_mark: |
  | GFM  | :white_check_mark: |

  Check out the spec at https://github.github.com/gfm/
  """,
  extension: [
    strikethrough: true,
    tagfilter: true,
    table: true,
    autolink: true,
    tasklist: true,
    footnotes: true,
    shortcodes: true,
  ],
  parse: [
    smart: true,
    relaxed_tasklist_matching: true,
    relaxed_autolinks: true
  ],
  render: [
     github_pre_lang: true,
     escape: true
  ]
) |> IO.puts()
#=> <p>GitHub Flavored Markdown 🚀</p>
#=> <ul>
#=>   <li><input type="checkbox" checked="" disabled="" /> Task A</li>
#=>   <li><input type="checkbox" checked="" disabled="" /> Task B</li>
#=>   <li><input type="checkbox" disabled="" /> Task C</li>
#=> </ul>
#=> <table>
#=>   <thead>
#=>     <tr>
#=>       <th>Feature</th>
#=>       <th>Status</th>
#=>     </tr>
#=>   </thead>
#=>   <tbody>
#=>     <tr>
#=>       <td>Fast</td>
#=>       <td>✅</td>
#=>     </tr>
#=>     <tr>
#=>       <td>GFM</td>
#=>       <td>✅</td>
#=>     </tr>
#=>   </tbody>
#=> </table>
#=> <p>Check out the spec at <a href="https://github.github.com/gfm/">https://github.github.com/gfm/</a></p>

Code Syntax Highlighting

MDEx.to_html(~S"""
```elixir
String.upcase("elixir")
```
""",
features: [syntax_highlight_theme: "catppuccin_latte"]
) |> IO.puts()
#=> <pre class=\"autumn highlight\" style=\"background-color: #282C34; color: #ABB2BF;\">
#=>   <code class=\"language-elixir\" translate=\"no\">
#=>     <span class=\"namespace\" style=\"color: #61AFEF;\">String</span><span class=\"operator\" style=\"color: #C678DD;\">.</span><span class=\"function\" style=\"color: #61AFEF;\">upcase</span><span class=\"\" style=\"color: #ABB2BF;\">(</span><span class=\"string\" style=\"color: #98C379;\">"elixir"</span><span class=\"\" style=\"color: #ABB2BF;\">)</span>
#=>   </code>
#=> </pre>

Demo and Samples

A livebook and a script are available to play with and experiment with this library, or you can check out all available samples at https://mdex-c31.pages.dev

Used By

Using it and want your project listed here? Please send a PR!

Benchmark

A simple script is available to compare existing libs:

Name              ips        average  deviation         median         99th %
cmark         22.82 K      0.0438 ms    ±16.24%      0.0429 ms      0.0598 ms
mdex           3.57 K        0.28 ms     ±9.79%        0.28 ms        0.33 ms
md             0.34 K        2.95 ms    ±10.56%        2.90 ms        3.62 ms
earmark        0.25 K        4.04 ms     ±4.50%        4.00 ms        4.44 ms

Comparison:
cmark         22.82 K
mdex           3.57 K - 6.39x slower +0.24 ms
md             0.34 K - 67.25x slower +2.90 ms
earmark        0.25 K - 92.19x slower +4.00 ms

Motivation

Note that MDEx is the only one that syntax highlights out-of-the-box which contributes to make it slower than cmark.

To finish, a friendly reminder that all libs have their own strengths and trade-offs.

Looking for help with your Elixir project?

DockYard logo

At DockYard we are ready to help you build your next Elixir project. We have a unique expertise in Elixir and Phoenix development that is unmatched and we love to write about Elixir.

Have a project in mind? Get in touch!

Acknowledgements