Server-side renderer for Quill (Slab) Delta: keep Delta as your source of truth in storage, rehydrate Quill for editing, and render HTML for display surfaces (web UI, emails, PDFs).
30-Second Start
# 1) Add dependency
# {:delta_html, "~> 0.5"}
# 2) Convert Quill Delta to HTML
DeltaHtml.to_html([
%{"insert" => "Hello "},
%{"attributes" => %{"bold" => true}, "insert" => "world"},
%{"insert" => "!\n"}
])
# => "<p>Hello <strong>world</strong>!</p>"What This Is Useful For
Typical production workflow with Quill:
- Use Quill in your frontend edit form.
- Save only the Delta JSON in your backend/database.
- When user edits again, load that Delta back into Quill (rehydrate editor state).
- When rendering rich text (web UI, emails, PDFs), convert stored Delta to HTML with
DeltaHtml.
This keeps a single source of truth (Delta) while generating HTML only when you need to display content.
Usage
iex> DeltaHtml.to_html([%{"insert" => "word\n"}])
"<p>word</p>"
# With whitespace preservation
iex> DeltaHtml.to_html([%{"insert" => "a b\tc\n"}], preserve_whitespace: true)
"<div style=\"white-space: pre-wrap;\"><p>a b\tc\n</p></div>"Quill CSS Mode
Use quill_css: true to emit Quill-style classes for block attributes:
iex> DeltaHtml.to_html(
...> [%{"insert" => "x"}, %{"attributes" => %{"align" => "center", "direction" => "rtl", "indent" => 2}, "insert" => "\n"}],
...> quill_css: true
...> )
"<p class=\"ql-align-center ql-direction-rtl ql-indent-2\">x</p>"Note: this mode is intentionally not identical to Quill getSemanticHTML() for all attributes. Quill semantic output commonly uses inline styles for align/direction, while quill_css: true prefers classes for easier reuse of Quill theme CSS.
Supported Features
Inline
- ✅ Background Color - background
- ✅ Bold - bold
- ✅ Color - color
- ✅ Font - font (only
serifandmonospace) - ✅ Inline Code - code
- ✅ Italic - italic
- ✅ Link - link
- ✅ Size - size (only
small,large, andhuge) - ✅ Strikethrough - strike
- ✅ Superscript/Subscript - script
- ✅ Underline - underline
Block
- ✅ Blockquote - blockquote
- ✅ Header - header
- ✅ Indent - indent
- ✅ List - list
- ✅ Text Alignment - align
- ✅ Text Direction - direction
- ❌ Code Block - code-block
- ❌ Formula - formula (requires KaTeX)
- ❌ Image - image
- ❌ Video - video
Plugins
- ✅ quill-mention - output as
#{denotation_char}#{id}, e.g.+name
Extensibility
There are currently no extension points for additional formats or plugins. The implementation is a fairly short single file, so copying and adapting it is straightforward.
Alternatives
- Convert in browser
quill.getSemanticHTML(0)- Con: Need to store Delta and HTML.
- Con: Need to sanitize HTML on server.
- Con: Less control over output (separate transform pass on server?), especially for plugins like quill-mention.
- NIF
- Rust: quill-core-rs (untested)
- Markdown instead of Delta/Quill
Quill Parity Harness
The repository includes a JS harness under quill_harness/ that renders Delta with Quill 2 (getSemanticHTML) and feeds parity checks in Elixir tests.
mix quill.setup
mix test
Development Checks
mix precommit
mix precommit runs:
mix format --check-formattedmix compile --warnings-as-errorsmix credo --strictmix dialyzermix test --warnings-as-errors
Styler is configured as a formatter plugin and runs through mix format (not as a standalone Mix task).