MDExKatex (MDExKatex v0.1.1)
View SourceUsage
Mix.install([
{:mdex_katex, "~> 0.1"}
])
markdown = """
# Einstein's Mass-Energy Equivalence
```math
E = mc^2
```
The quadratic formula:
```math
x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}
```
"""
mdex = MDEx.new(markdown: markdown) |> MDExKatex.attach()
MDEx.to_html!(mdex) |> IO.puts()
#=>
# <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.css">
# <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.js"></script>
# <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body, {delimiters: [{left: '$$', right: '$$', display: true}]});"></script>
# <script>
# document.addEventListener("DOMContentLoaded", () => {
# document.querySelectorAll('.katex-block').forEach(el => {
# const latex = el.dataset.latex;
# if (latex) {
# katex.render(latex, el, {
# displayMode: true,
# throwOnError: false,
# trust: true
# });
# }
# });
# });
# </script>
# <h1>Einstein's Mass-Energy Equivalence</h1>
# <div id="katex-1" class="katex-block" phx-update="ignore" data-latex="E = mc^2"></div>
# <p>The quadratic formula:</p>
# <div id="katex-2" class="katex-block" phx-update="ignore" data-latex="x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}"></div>Note: Both math and katex code fences are supported.
See attach/2 for integration examples (static HTML, Phoenix LiveView, custom styling) and configuration options.
Summary
Functions
Attaches the MDExKatex plugin into the MDEx document.
Types
@type katex_block_attrs() :: (seq :: pos_integer() -> String.t())
Functions
@spec attach( MDEx.Document.t(), keyword() ) :: MDEx.Document.t()
Attaches the MDExKatex plugin into the MDEx document.
- KaTeX is loaded from https://www.jsdelivr.com/package/npm/katex
- Renders mathematical expressions using LaTeX syntax
- Recognizes both
mathandkatexcode fences
Options
:katex_block_attrs(katex_block_attrs/0) - Function that generates the<div>tag attributes for math code blocks.:katex_init(String.t/0) - The HTML tag(s) to inject into the document to initialize KaTeX. Ifnil, the default script is used (see below).
:katex_block_attrs
Whenever a code block tagged as math or katex is found, it gets converted into a <div> tag using the following function to generate its attributes:
block_attrs = fn seq -> ~s(id="katex-#{seq}" class="katex-block" phx-update="ignore") end
mdex = MDEx.new() |> MDExKatex.attach(katex_block_attrs: block_attrs)Which results in:
<div id="katex-1" class="katex-block" data-latex="E = mc^2" phx-update="ignore"></div>You can override it to include or manipulate the attributes but it's important to maintain unique IDs for each instance, otherwise the KaTeX rendering will not work correctly, for eg:
fn seq -> ~s(id="katex-#{seq}" class="katex-block formula" phx-hook="KaTeXHook" phx-update="ignore") end:katex_init
The option :katex_init can be used to manipulate how KaTeX is initialized. By default, the following script is injected into the top of the document:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16/dist/contrib/auto-render.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll('.katex-block').forEach(el => {
const latex = el.dataset.latex;
if (latex) {
katex.render(latex, el, {
displayMode: true,
throwOnError: false,
trust: true
});
}
});
});
</script>That script works well on static documents but you'll need to adjust it to initialize KaTeX in environments that requires waiting for the DOM to be ready.
Examples
See the examples directory for complete working examples.
Static HTML
The output includes all necessary scripts and can be used directly:
html = MDEx.new(markdown: markdown) |> MDExKatex.attach() |> MDEx.to_html!()
File.write!("output.html", html)For embedding in existing HTML documents, extract content between initialization scripts and your markdown content.
See examples/static.exs for a complete working example.
Phoenix LiveView
To use MDExKatex with Phoenix LiveView, you can:
- Load KaTeX (via CDN or npm)
- Create a LiveView hook to render formulas
- Configure MDExKatex with the appropriate attributes
Option 1: Using CDN
In your layout:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.js"></script>Option 2: Using npm
Install KaTeX as a dependency:
cd assets && npm install katex
In your assets/js/app.js:
import katex from 'katex';
import 'katex/dist/katex.min.css';
let hooks = {
KaTeXHook: {
mounted() {
const elements = this.el.querySelectorAll('.katex-block');
elements.forEach(el => {
const latex = el.dataset.latex;
if (latex) {
katex.render(latex, el, {
displayMode: true,
throwOnError: false,
trust: true
});
}
});
}
}
}
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: hooks})Using in LiveView
html =
MDEx.new(markdown: markdown)
|> MDExKatex.attach(
katex_init: "", # already initialized
katex_block_attrs: fn seq ->
~s(id="katex-#{seq}" class="katex-block" phx-hook="KaTeXHook" phx-update="ignore")
end
)
|> MDEx.to_html!()
assign(socket, html: {:safe, html})}Note that you can attach a JS hook per formula or in a parent element to handle all formulas at once, depending on your needs.
See examples/live_view.exs for a complete working example with both individual hooks and global hooks patterns.
Custom Styling
Target the .katex-block class:
.katex-block {
padding: 1em;
margin: 1em 0;
background: #f5f5f5;
border-radius: 4px;
}