Packages
mdex
0.12.3
0.13.3
0.13.2
0.13.1
0.13.0
0.12.5
retired
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Fast and extensible Markdown for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
guides/plugins.md
# Plugins
Plugins are reusable modules that extend MDEx's functionality by registering options, appending processing steps, and transforming the document tree. They provide a clean way to package and share custom behavior.
## Using Existing Plugins
There are three ways to attach plugins to a document:
### Via `MDEx.new/1`
The most common approach is passing plugins when creating a new document:
```elixir
MDEx.new(markdown: "# Hello", plugins: [MyPlugin])
|> MDEx.to_html!()
```
You can pass options to plugins using a tuple:
```elixir
MDEx.new(markdown: "# Hello", plugins: [{MyPlugin, custom_option: "value"}])
|> MDEx.to_html!()
```
### Via `:plugins` option in `MDEx.to_html/2`
For convenience, you can pass plugins directly to rendering functions:
```elixir
MDEx.to_html!("# Hello", plugins: [MyPlugin])
```
### Via `MDEx.Document.put_plugins/2`
For more control, attach plugins manually to a document:
```elixir
MDEx.new(markdown: "# Hello")
|> MDEx.Document.put_plugins([MyPlugin])
|> MDEx.to_html!()
```
You can also call the plugin's `attach/2` function directly:
```elixir
MDEx.new(markdown: "# Hello")
|> MyPlugin.attach(custom_option: "value")
|> MDEx.to_html!()
```
## Creating Custom Plugins
A plugin is any module that implements an `attach/2` function. This function receives a document and options, and returns a modified document:
```elixir
defmodule MyPlugin do
alias MDEx.Document
def attach(document, options \\ []) do
document
|> Document.register_options([:my_option])
|> Document.put_options(options)
|> Document.append_steps(my_step: &my_step/1)
end
defp my_step(document) do
# Transform the document
document
end
end
```
## Document Pipeline Functions
These `MDEx.Document` functions are commonly used when building plugins:
### `register_options/2`
Registers custom option keys so they can be stored in the document:
```elixir
Document.register_options(document, [:theme_color, :enable_feature])
```
### `put_options/2`
Sets values for registered options:
```elixir
Document.put_options(document, theme_color: "blue", enable_feature: true)
```
### `append_steps/2`
Adds processing steps that run when the document is rendered. Steps are functions that receive and return a document:
```elixir
Document.append_steps(document,
validate: &validate/1,
transform: &transform/1
)
```
### `update_nodes/3`
Updates nodes matching a selector with a transformation function:
```elixir
Document.update_nodes(document, MDEx.Text, fn node ->
%{node | literal: String.upcase(node.literal)}
end)
```
## Example Plugin
Here's a complete example that adds custom attributes to code blocks:
```elixir
defmodule CodeBlockEnhancer do
alias MDEx.Document
def attach(document, options \\ []) do
document
|> Document.register_options([:code_class])
|> Document.put_options(options)
|> Document.append_steps(enhance_code_blocks: &enhance_code_blocks/1)
end
defp enhance_code_blocks(document) do
class = Document.get_option(document, :code_class) || "highlight"
MDEx.traverse_and_update(document, fn
%MDEx.CodeBlock{} = node ->
%MDEx.HtmlBlock{literal: ~s(<pre class="#{class}"><code>#{node.literal}</code></pre>)}
node ->
node
end)
end
end
```
Usage:
```elixir
MDEx.to_html!(markdown, plugins: [{CodeBlockEnhancer, code_class: "syntax-highlight"}])
```