Is it possible to render markdown with Phoenix 1.7?

These eex engines are not composable pieces you can easy make work in any arbirary order. As you noticed Earmark cannot compile things with (h)eex in it and heex cannot compile non html’ish content.
With just EEx you could go the direction of EEx first (it doesn’t care for the content around its tags) to compose a final markdown document and then use Earmark to turn that into html. That won’t give you any integration with heex though.

In the end you’d either need a markdown parser, which can turn markdown with embedded heex/eex tags into html with heex/eex tags and pass that into the heex engine or even a single engine doing both.

I’d suggest a much simpler option, which I’m using for my website: Use NimblePublisher for handling the markdown files. Implement a custom parser, which detects some custom comments <!-- [Component] --> and stores that within the parsed data. When rendering the markdown turn that into a live_render(@conn, …).

stream = Stream.cycle([:html, :live])
    parts = :binary.split(assigns.content, ["<!-- [", "] -->"], [:global])
    assigns = assigns |> assign(:parts, Enum.zip([stream, parts]))

    ~H"""
    <%= for p <- @parts do %>
      <%= case p do %>
        <% {:live, live} -> %>
          <%= live_render(@conn, Module.concat([live])) %>
        <% {:html, html} -> %>
          <%= Phoenix.HTML.raw(html) %>
      <% end %>
    <% end %>
    """