A small allow-listed HTML subset, for the one place the document's own JSON→HTML pipeline does not reach: header and footer slots, which are typed as text rather than edited as a Tiptap document.
iex> Tiptapex.Renderer.Markup.to_html("<b>Acme</b> S.A.") |> IO.iodata_to_binary()
"<b>Acme</b> S.A."It follows the same rule as the rest of Tiptapex.Renderer: nothing from
the input is ever emitted verbatim. The string is tokenised, each tag is
matched against a closed allow-list, and the output is rebuilt with
Tiptapex.Renderer.HTML. Anything unrecognised — an unknown tag, a
malformed one, a stray attribute — becomes escaped text, so the worst a
mis-parse can do is show the user their own markup:
iex> Tiptapex.Renderer.Markup.to_html("<script>alert(1)</script>") |> IO.iodata_to_binary()
"<script>alert(1)</script>"What is allowed
- inline —
b,strong,i,em,u,s,small,sub,sup,span,a,br,img - block —
p,div,h1…h6
Attributes: style (each declaration's property must be in the allow-list
and its value must pass Tiptapex.Renderer.URL.safe_css_value/1), href
on a, src/alt/width/height on img, and title. Everything else
is dropped.
Unclosed tags are closed at the end; a closing tag that doesn't match the innermost open one is dropped.
Summary
Functions
The tag names this module renders.
True when text contains at least one tag this module would render.
Renders the allow-listed subset of text as escaped, rebuilt iodata.
Functions
@spec allowed_tags() :: [binary()]
The tag names this module renders.
True when text contains at least one tag this module would render.
Callers use it to decide whether a plain-text channel is enough —
wkhtmltopdf's --header-left takes text, not markup, so a slot with
markup has to go through --header-html instead.
iex> Tiptapex.Renderer.Markup.markup?("Page {page}")
false
iex> Tiptapex.Renderer.Markup.markup?("Page <b>{page}</b>")
true
Renders the allow-listed subset of text as escaped, rebuilt iodata.
Non-binaries render as "".