LiveView: socket |> put_root_layout overwrite root layout

In normal controllers, to overwrite the root layout I would use

conn
|> put_layout(false)
|> put_root_layout(false)
|> render("any.html", foo: bar)

to don’t use root.html.heex or anything else.

How can I achieve that with LiveView?

AFAIK there are a few ways to do this depending on what you want to do and how you’re rendering the LiveView.

To remove or replace the "live.html" layout on an individual LiveView just return from your mount/3 callback with {:ok, socket, layout: false} or {:ok, socket, layout: {LayoutView, "custom_layout.html"}.

You can also pass an alternative layout as an option to use Phoenix.LiveView.

defmodule MyAppWeb.PageLive do
  use Phoenix.LiveView, layout: {LayoutView, "custom_layout.html"}
end

You can perform this override in the def live_view block of my_app_web.ex if you want to apply it app-wide whenever you use MyAppWeb, :live_view

To override the "root.html" layout you can pass :root_layout as an option to live_session in your router.ex

scope "/", MyAppWeb do
  pipe_through :browser

  live_session :default, root_layout: false do
  # or root_layout: {LayoutView, :custom_layout}
    live "/page", PageLive
  end
end

If you are rendering your LiveView from a controller with live_render(conn, PageLive) then you can do it the old-fashioned way you already know.

3 Likes

To override the "root.html" layout you can pass :root_layout as an option to live_session in your router.ex

This did it. Thank you very much.

callback with {:ok, socket, layout: false} or

Does actually not work. It expects an alternative layout as you described with

{:ok, socket, layout: {LayoutView, “custom_layout.html”}

which then could be empty.

1 Like

:thinking: It definitely works for me. I have used it in a project and made sure to test each of these methods before answering. I’m testing it right now with both live_rendered liveviews and router mounted liveviews and both are working. It’s only good for changing the inner layout, not the root layout, fwiw. Also, this is v.0.17.10

Edit: you’re right that layout: false does not work as an option for use Phoenix.LiveView, that is the only one I did not directly test : ) But it does work in the return value for mount/3. Correcting the original post for posterity

1 Like

Sorry, I quoted the wrong part, within the LiveView page your are correct, this works. The part where I got the error message was:

use Phoenix.LiveView, layout: false

With the message:

:layout expects a tuple of the form {MyLayoutView, "my_template.html"}, got: false

2 Likes

Testing :layout on a live_view mount in Phoenix 1.7.1.

The error message is leading to a View concept:

:layout expects a tuple of the form {MyLayoutView, :my_template} or false, got: :menu

But it’s perfectly happy with {ProjectWeb.Layouts, :menu}:

  def mount(_params, _session, socket) do
    {:ok, socket, layout: {ProjectWeb.Layouts, :menu}}
  end

provided, a menu.html.heex sits in the layouts folder (and therefore embedded by layouts.ex which defines ProjectWeb.Layouts module).

1 Like