Building embedded/nested HTML structures with view functions

How should one write a view function that produces nested HTML, such as the safe version of:

    I have a <strong>strong</strong> opinion.

The following works:

def strong_opinion do
  shout = content_tag(:strong, "strong")
  Phoenix.HTML.raw "I have a #{safe_to_string shout} opinion."
end

But the safe_to_string then raw sequence seems awkward. Is that the right way to do it?

You can use the ~E sigil, that allows you to inject eex template inline:

def strong_opinion do
  ~E"""
  I have a <%= content_tag :strong, "strong" %> opinion.
  """
end
8 Likes

I today realized that Phoenix rendering doesn’t work with strings, but rather with Erlang iolists. That means an invocation like:

        <%= shout %>

… works when shout is defined like this:

def shout do
  ["I have a ", content_tag(:strong, "strong"), " opinion"]
end

So building nested structures is surprisingly easy, including special handling of empty children:

  def wrap_in_section(iolist) when length(iolist) == 0, do: []
  def wrap_in_section(iolist) do
    [tag(:hr),
     content_tag(:p, iolist, class: "lead")]
  end

Yep, eex’s are very simple, it is basically a compiled pre-made iolist that has a few bits of its filled in at render time, it is very fast, and functional. :slight_smile: