Skip to content

dannote/phoenix_streamdown

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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, word-level streaming animations, and zero client-side JavaScript.

Installation

def deps do
  [{:phoenix_streamdown, "~> 1.0.0-beta"}]
end

Usage

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.

Streaming animations

Add word-level fade-in like Vercel's Streamdown:

<.markdown content={@response} streaming animate="fadeIn" />

Include the CSS (fadeIn, blurIn, slideUp):

@import "../../deps/phoenix_streamdown/priv/static/phoenix_streamdown.css";

How it works

  1. Remend — auto-closes incomplete syntax (**bold**bold**, unclosed fences, partial links)
  2. Blocks — splits into independent blocks so earlier ones are stable
  3. MDEx — renders each block to HTML server-side (Rust-backed)
  4. 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.server

Documentation

HexDocs — attributes, customization (themes, CSS classes, stable IDs, MDEx options).

License

MIT

About

Streaming markdown renderer for Phoenix LiveView, optimized for LLM output

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors