HEEx Integration
View SourceMDEx integrates with Phoenix LiveView's HEEx templates, allowing you to use Markdown alongside Phoenix components, phx-* bindings, and Elixir expressions.
When to Use HEEx Integration
Use HEEx integration when you need:
- Phoenix components (like
<.link>,<.button>, or custom components) inside Markdown - LiveView bindings (
phx-click,phx-submit, etc.) - Elixir expressions that evaluate at runtime (
{@var})
For static Markdown without Phoenix components, use the regular ~MD[...]HTML modifier or MDEx.to_html/2 instead.
Setup
Add use MDEx to your module to enable both require MDEx (for to_heex/2) and import MDEx.Sigil (for the ~MD sigil):
defmodule MyAppWeb.PageLive do
use Phoenix.LiveView
use MDEx
# Now you can use ~MD[...]HEEX and MDEx.to_heex/2
endTwo Approaches
~MD[...]HEEX Sigil (Compile-time)
The preferred approach for LiveView templates. The Markdown is parsed at compile-time for optimal performance:
def render(assigns) do
~MD"""
# Welcome, {@username}!
<.link href={@profile_url}>View Profile</.link>
"""HEEX
endMDEx.to_heex/2 Macro (Runtime)
For dynamic content or when the sigil isn't available. The template is evaluated at runtime:
def render(assigns) do
markdown = fetch_markdown_from_database()
MDEx.to_heex!(markdown, assigns: assigns)
endNote: Calling to_heex/2 repeatedly at runtime may impact performance. Prefer the sigil when possible.
Using Assigns
Pass variables to your Markdown templates using the {@var} syntax:
def render(assigns) do
~MD"""
Welcome back, **{@user.name}**!
You have {@notification_count} unread notifications.
"""HEEX
endThe old <%= @var %> EEx syntax also works for compatibility.
Phoenix Components
Use any Phoenix component directly in your Markdown:
~MD"""
# Navigation
- <.link navigate={~p"/home"}>Home</.link>
- <.link navigate={~p"/about"}>About</.link>
<.button phx-click="save">Save Changes</.button>
<MyAppWeb.Components.card title={@card_title}>
Card content here
</MyAppWeb.Components.card>
"""HEEXComponent imports are not automatic
MDEx does not automatically import components. To use function components with the dot notation:
- Import
Phoenix.Componentfor core components like<.link> - Import your app's components module (e.g.,
import MyAppWeb.CoreComponents) - Or use fully qualified names:
<Phoenix.Component.link href="/">Home</Phoenix.Component.link>
In Phoenix applications, use MyAppWeb, :live_view typically handles these imports for you.
Elixir Expressions
Embed Elixir expressions using curly braces:
~MD"""
Today is _{Calendar.strftime(DateTime.utc_now(), "%B %d, %Y")}_
<%= for item <- @items do %>
- {item.name}: **{item.status}**
<% end %>
"""HEEXConverting HEEx to HTML String
When you need the final HTML as a string (e.g., for emails or static pages):
MDEx.to_heex!(markdown, assigns: assigns)
|> MDEx.to_html!()Full Example
defmodule MyAppWeb.BlogLive do
use Phoenix.LiveView
use MDEx
def mount(_params, _session, socket) do
{:ok, assign(socket, title: "My Post", likes: 42)}
end
def render(assigns) do
~MD"""
# {@title}
This post has **{@likes}** likes.
<.button phx-click="like">Like this post</.button>
---
Built with <.link href="https://hex.pm/packages/mdex">MDEx</.link>
"""HEEX
end
def handle_event("like", _, socket) do
{:noreply, update(socket, :likes, &(&1 + 1))}
end
end