Using multiple templates with a singe LiveView

We’re creating a new site using Phoenix 1.7 and LiveView 20.0. However, some of the pages such as Terms and Privacy pages were implemented using dead views. It was questioned whether this was a good idea or not since it’s mixing live and dead views. The critique can be summed up as:

  1. Nothing is gained by using a dead view
  2. There are a few downsides:
    1. Using a Controller triggers a full GET request, which is less performant than using patch to move within the same LiveView, or navigate to move between LiveViews. The difference is small but noticeable.
    2. Navigating back from a dead view to a LiveView has an undesirable side effect: forcing the entire LiveView to be reloaded, which scrolls the user to the top of the page, losing their previous position.

Since the pages in question are just static HTML (e.g., Terms of Service and Privacy Policy), this is the existing setup:

router.ex

scope "/", ExampleWeb do
  pipe_through :browser

  get "/privacy", PageController, :privacy
  get "/terms", PageController, :terms
end

page_controller.ex

defmodule ExampleWeb.PageController do
  use ExampleWeb, :controller

  def privacy(conn, _params) do
    render(conn, :privacy)
  end

  def terms(conn, _params) do
    render(conn, :terms)
  end
end

Along with privacy.html.heex and terms.html.heex files.

How would I reproduce this setup using a LiveView? I want a single LiveView that can render multiple templates based on the :live_action with each template being defined in a separate _.html.heex file. I understand that having a single LiveView returning different static HTML templates kind of defeats the purpose of LiveView.

As an aside, is it correct that mixing live/dead views is bad practice?

I’m new to LiveView so I really appreciate any insights anyone has. Cheers!

Is it true that mixing live/dead views is bad practice?

No, not at all. Each has their place although I would argue LiveView everywhere is easier to manage in most cases

To repro your setup with LiveView, I would dispatch different render functions based on the socket.assigns.live_action

In your router:

live "/terms", PageLive, :terms
live "/privacy", PageLive, :privacy

and LiveView

@impl Phoenix.LiveView
def render(%{live_action: :privacy} = assigns) do
~H"""
Privacy page template
"""
end

def render(%{live_action: :terms} = assigns) do
~H"""
T&C's
"""
end

Off the top of my head, I’m not sure how you would do so with actual separate template files. Perhaps someone else has better insight into that. I prefer having the render functions live in the single LiveView file itself anyways though