PhoenixStreamdown
Streaming markdown renderer for Phoenix LiveView, optimized for LLM output.
Inspired by Streamdown and vue-stream-markdown, but built to fully leverage LiveView — server-side rendering, automatic DOM diffing, and zero client-side JavaScript.
Installation
def deps do
[{:phoenix_streamdown, "~> 1.0.0-beta"}]
endUsage
use PhoenixStreamdown<.markdown content={@response} streaming={@streaming?} />
That's it. Pass content as a markdown string, set streaming to true while tokens are arriving. Completed blocks are frozen with phx-update="ignore" — only the last block re-renders on each token.
How it works
- Remend — auto-closes incomplete syntax (
**bold→**bold**, unclosed fences, partial links) - Blocks — splits into independent blocks so earlier ones are stable
- MDEx — renders each block to HTML server-side (Rust-backed)
- LiveView — diffs only the active block, skips the rest
On a 56-block document, this is ~7x less server work and ~460x smaller diffs per token compared to re-rendering the full document each time.
Example
A full chat app with ReqLLM streaming is in the example/ directory. Run it:
cd example
cp .env.example .env # add your OpenRouter API key
mix setup
mix phx.serverDocumentation
HexDocs — attributes, customization (themes, CSS classes, stable IDs, MDEx options).
License
MIT