# Phoenix Multiple Layouts

**URL:** <https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905>\
**Category:** Questions\
**Tags:** authentication, plug, phoenix, frontend, learning-elixir, liveview, layouts\
**Created:** [August 28, 2023, 3:54pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905 "2023-08-28T15:54:43Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![jstone](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/j/ee7513/32.png) [@jstone](https://forum.elixirforum.com/u/jstone)\
**Post date:** [August 28, 2023, 3:54pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/1 "2023-08-28T15:54:43Z")

</div>

Hello, Im having issue, having multiple layouts.

1. Layouts for Admin (System Access / Portal / Data Management)
2. Layouts for Login / Register

I create new plug for router just to handle different layouts for login

```elixir
pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {WebApp.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :fetch_current_user
  end

  pipeline :login_page do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {WebApp.AuthenticationLayouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :fetch_current_user
  end

```

And I copy the original layouts and make the layouts components as below :

 ![image](https://forum.elixirforum.com/uploads/default/original/3X/d/2/d21f5ea60da175dff486459eb18d238c190e8886.png)

This will make whenever I visit link `/users/log_in` (Using Original Phx Auth) it will render root file from folder components `auth_layouts`.

However when I use code `<%= @inner_content %>` inside root file `auth_layouts/root.html.heex` it will render page from file `layouts/app.html.heex` instead of `auth_layouts/app.html.heex`. Please suggest/assist where can I change to make it render `auth_layouts/app.html.heex`. Thanks. Any response is highly appreciated

side note : Sorry if the question kinda noob, this is my first project using Phx Framework. Excited but can’t find the solution.

---

<div class="post-metadata">

**Author:** ![sbuttgereit](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sbuttgereit/32/30162_2.png) [@sbuttgereit](https://forum.elixirforum.com/u/sbuttgereit)\
**Post date:** [August 28, 2023, 4:16pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/2 "2023-08-28T16:16:18Z")

</div>

I’m not the best person to answer this, but one thing that immediately comes to mind is have you checked your `web_app.ex` file (making assumptions about your naming based on what I see in your code example) and what it may/may not do with layouts? By default there’s some layout assignment happening there and my recollection was that it could interfere with the plug based stuff.

I use different layouts as well and rather than trying to control layouts via plugs, I created entries in my equivalent to `web_app.ex` to deal with the layouts and other kinds of setup as appropriate to the type of form.

Again… I could be way off-base and there are others here that can probably be more helpful…

---

<div class="post-metadata">

**Author:** ![jstone](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/j/ee7513/32.png) [@jstone](https://forum.elixirforum.com/u/jstone)\
**Post date:** [August 28, 2023, 4:25pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/3 "2023-08-28T16:25:07Z")

</div>

Hello,

Yes I already tried that solution, however this only applicable for 1 layouts, I’m not sure how to register multiple layouts. Here what I do

```elixir
def live_view do
    quote do
      use Phoenix.LiveView, layout: {WebApp.Layouts, :app}

      unquote(html_helpers())
    end
  end

```

Change to

```elixir
def live_view do
    quote do
      use Phoenix.LiveView, layout: {WebApp.AuthenticationLayouts, :app}

      unquote(html_helpers())
    end
  end

```

This will successfully render `auth_layouts/app.html.heex`. However what If I wanna use the original layouts?

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [August 28, 2023, 4:25pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/4 "2023-08-28T16:25:41Z")

</div>

Ya, this is what I do.

I don’t have multiple directories for layouts since there is only one layout per different section but I have;

```elixir
my_app_web/layouts/root.html.heex
my_app_web/layouts/public.html.heex
my_app_web/layouts/admin.html.heex

```

```elixir
def live_view do
  quote do
    use Phoenix.LiveView,
      layout: {GelaWeb.Layouts, :public}

    unquote(html_helpers())
  end
end

def admin_live_view do
  quote do
    use Phoenix.LiveView,
      layout: {GelaWeb.Layouts, :admin}

    unquote(html_helpers())
  end
end

```

Then:

```elixir
defmodule MyAppWeb.SomeAdminPage do
  use MyAppWeb, :admin_live_view
end

```

You can do the same with the `controller` helper.

I’m sure you can make this work with directories if you use a string instead of an atom.

---

<div class="post-metadata">

**Author:** ![sbuttgereit](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sbuttgereit/32/30162_2.png) [@sbuttgereit](https://forum.elixirforum.com/u/sbuttgereit)\
**Post date:** [August 28, 2023, 4:26pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/5 "2023-08-28T16:26:08Z")

</div>

[I had posted my code, but @sodapopcan did so before me and mine had nothing new to offer on that response… can’t delete my comment so… clearing it.]

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [August 28, 2023, 4:28pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/6 "2023-08-28T16:28:41Z")

</div>

Ha, sorry, didn’t realize you were replying!!

---

<div class="post-metadata">

**Author:** ![LostKobrakai](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/32/3072_2.png) [@LostKobrakai](https://forum.elixirforum.com/u/LostKobrakai)\
**Post date:** [August 28, 2023, 4:28pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/7 "2023-08-28T16:28:51Z")

</div>

You can return a layout from `mount/3` like so: `{:ok, socket, layout: {module, atom}}`. You can also use `live_session` to change the layout for a bunch of liveviews. No need to drop down to the macros to do that.

---

<div class="post-metadata">

**Author:** ![jstone](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/j/ee7513/32.png) [@jstone](https://forum.elixirforum.com/u/jstone)\
**Post date:** [August 28, 2023, 4:30pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/8 "2023-08-28T16:30:26Z")

</div>

Thanks @sodapopcan This give me the idea. I can create a custom function, and on a specific / any live view that I need to be different layouts, I can use that custom function. Thanks.

Below are my solution. Create new custom function on `web_app.ex`

```elixir
def live_view_login do
    quote do
      use Phoenix.LiveView, layout: {WebApp.AuthenticationLayouts, :app}

      unquote(html_helpers())
    end
  end

```

and on LiveView use `use WebApp, :live_view_login` instead of using use `WebApp, :live_view_login` (the original)

Thanks guys @sodapopcan @sbuttgereit @LostKobrakai , Really appreciate the help. Resolved my issue.

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [August 28, 2023, 4:31pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/9 "2023-08-28T16:31:12Z")

</div>

Ya, I remember I was doing with this then switched to the macro helper version, I can’t remember quite why. I do add some extra helpers in the `admin` route ~~though those could probably be moved to hooks~~ ← nm, that doesn’t make any sense, lol. Ya, I think it was just because I had additional helpers but that was so long ago now that it is something I just do. I could re-evaluate.

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [August 28, 2023, 4:32pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/10 "2023-08-28T16:32:23Z")

</div>

I’d give heed to @LostKobrakai’s answer, though: you can also pass a layout to [live\_session](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Router.html#live_session/3).

---

<div class="post-metadata">

**Author:** ![jstone](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/j/ee7513/32.png) [@jstone](https://forum.elixirforum.com/u/jstone)\
**Post date:** [August 28, 2023, 4:35pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/11 "2023-08-28T16:35:36Z")

</div>

Thanks, This also will allow to override the layouts

---

<div class="post-metadata">

**Author:** ![hashtemptable](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/hashtemptable/32/38387_2.png) [@hashtemptable](https://forum.elixirforum.com/u/hashtemptable)\
**Post date:** [September 1, 2023, 1:23pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/12 "2023-09-01T13:23:46Z")

</div>

In my experience this does not work. It returns something like:

\*\* (ArgumentError) :layout expects a tuple of the form {MyLayoutView, :my\_template} or false, got: “pos.html”  
(phoenix\_live\_view 0.19.5) lib/phoenix\_live\_view/utils.ex:216: Phoenix.LiveView.Utils.normalize\_layout/2  
(phoenix\_live\_view 0.19.5) lib/phoenix\_live\_view/router.ex:276: anonymous fn/3 in Phoenix.LiveView.Router.validate\_live\_session\_opts/3  
(elixir 1.15.2) lib/enum.ex:2510: Enum.“-reduce/3-lists^foldl/2-0-”/3  
(phoenix\_live\_view 0.19.5) lib/phoenix\_live\_view/router.ex:240: Phoenix.LiveView.Router. **live\_session** /3  
lib/selfpos\_web/router.ex:82: (module)

---

<div class="post-metadata">

**Author:** ![LostKobrakai](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/32/3072_2.png) [@LostKobrakai](https://forum.elixirforum.com/u/LostKobrakai)\
**Post date:** [September 1, 2023, 1:25pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/13 "2023-09-01T13:25:31Z")

</div>

The new format requires – as stated – `{module, atom}` format not `{module, string}` or just `string`.

---

<div class="post-metadata">

**Author:** ![hashtemptable](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/hashtemptable/32/38387_2.png) [@hashtemptable](https://forum.elixirforum.com/u/hashtemptable)\
**Post date:** [September 1, 2023, 2:56pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/14 "2023-09-01T14:56:59Z")

</div>

thank you, I am struggling to find where in the docs it defines what should be in the tuple. Sticking to the overrides for now. Maybe if I continue learning the platform I will figure it out someday.

---

<div class="post-metadata">

**Author:** ![bo\_dev](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bo_dev/32/33875_2.png) [@bo\_dev](https://forum.elixirforum.com/u/bo_dev)\
**Post date:** [March 28, 2024, 3:56am UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/15 "2024-03-28T03:56:18Z")

</div>

Thank you, exactly what I was looking for!

Although I did the opposite of your admin and used a guest layout instead. Guest layout is used for all routes that require a user to be un-authenticated, such as login, register, reset password etc.

Coming from a Laravel background, it made more sense to me in my head 😃

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [October 4, 2024, 3:58pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/16 "2024-10-04T15:58:02Z")

</div>

I’m still sporadically getting pinged on this issue so I wanted to note that I regret [my answer](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/4) and I do NOT recommend doing this. [@LostKobrakai’s post](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/7) is the right way and should be the accepted answer. AFAIC it’s objectively better to use what the framework provides over writing custom macros.

I recently inherited a codebase that uses this pattern. As is almost guaranteed to happen when blazing your own trails additional concerns like authn ended up in these macros which should have been in `on_mount` callbacks. This was not only really confusing to figure out at first but the inclusion of the extra logic within macros caused unnecessary compile time dependencies.

Return `{:ok, socket, layout: {MyAppWeb.Layouts, :layout}` from `mount/3` or use `live_session, :my_session, layout: {MyAppWeb.Layouts, :layout}` in the router.

* * *

- [`mount/3`](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#c:mount/3)
- [`live_session/3`](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Router.html#live_session/3)
- [`on_mount/1`](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#on_mount/1)

---

<div class="post-metadata">

**Author:** ![sergio](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sergio/32/26966_2.png) [@sergio](https://forum.elixirforum.com/u/sergio)\
**Post date:** [February 17, 2025, 5:26pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/17 "2025-02-17T17:26:06Z")

</div>

Here’s how you do it for many live views, by using `live_session`.

```elixir
scope "/", MyAppWeb, host: "dietitian." do
  pipe_through [:browser]

  live_session :dietitian_dashboard, layout: {MyAppWeb.Layouts, :dietitian} do
    live "/", Dietitian.DashboardLive
  end
end

```

Make sure you have the file in:

`lib/my_app_web/components/layouts/dietitian.html.heex`

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [February 17, 2025, 8:23pm UTC](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/18 "2025-02-17T20:23:14Z")

</div>

This is also totally valid and actually what I do more often.

Also, I’m still getting likes on my [initial answer](https://forum.elixirforum.com/t/phoenix-multiple-layouts/57905/4) and wish I can delete it ☹
