adamu

adamu

Benefit of app layout being defined inline in Layouts, rather than in heex file?

I understand that heex code can either be defined inline with the ~H sigil, or placed into a .heex file and embedded with embed_templates.

I’m curious why Phoenix puts the root layout in a heex file, but the defines the app layout inline.

Is there a specific benefit to defining the app layout inline? Or is it simply because the default app layout is pretty small? Or maybe to provide an example of each method?

Marked As Solved

josevalim

josevalim

Creator of Elixir

`root` could work as a regular function. I just double checked by converting it in tidewave.ai and it worked just fine! And I believe this is true since Phoenix v1.6 (or v1.7?) when we unified everything to be function components.

So let’s answer this by parts.

First, why do we need layouts?

Mainly because LiveView pages need to denote some content that cannot be live updated. This is typically in the `head` tag. We know there are frameworks who have attempted to update and merge `head` tags but it is very easy to run into hard-to-debug JavaScript bugs and corner-cases in browser. So the root layout helps us denote the static part.

Who renders the layout? After all, we could have made it so all of your regular templates simply called `<Layout.root>`.

Per the above, we know that the contents of `<Layout.root>` cannot be updated and therefore they should not be re-rendered. If we made your template call it, the one rendered on every LiveVIew update, then we would always re-render the root layout too, only to later figure out a way to discard its updates, which would be wasteful.

Beyond the above, it is important to note that frameworks generally want to own how the layout is rendered because it can lead to UX improvements such as sending the layout upfront, up to the `body` tag, before your LiveView and Controllers get invoked. This would allow browsers to parse `head` tag while you are still runing queries and what not, leading to faster page loads. Of course, there are complications, such as what to do if you send the `head` and then you get an exception, but the point is that leaving the framework to control how the layout is rendered can be feature!

IMO, this is not about inheritance at all, especially because frameworks that do offer template inheritance allow you to extend the layout with additional information beyond the inner block, which we don’t. We intentionally keep the layout decoupled from the application contents because we want to have flexibility over it.

So why do we have root.html.heex?

The reason we moved the app layout to a component is because you can declare your own attributes and slots and we wanted to make it clear you should invoke it. You can’t do any of that with root layouts, so we kept them distinct to avoid confusion. Leading someone to think they should call `Layout.root` would most likely lead to disaster. :smiley:

TL;DR: the `app` and `root` layouts are defined differently as to signal users you are supposed to invoke the former but not the latter. That’s it.

Also Liked

BartOtten

BartOtten

For those who want to: phoenix_live_head | Hex

The change to a layout component was a major improvement for all the reasons José mentions. It also removed one extra segment of the docs now it’s clear in every template where the layout comes from.

bartblast

bartblast

Creator of Hologram

My suspicion is there’s significant historical inertia at play. Early SPAs were purely client-side - your server sent a minimal HTML shell with a static <head>, and JavaScript mounted in the body. This wasn’t really a choice. Without SSR, you needed that pre-rendered for bootstrap. The ecosystem then built around this pattern (React Helmet, etc.), and by the time SSR became standard, there wasn’t enough reason to revisit the architecture when the workarounds were “good enough”.

bartblast

bartblast

Creator of Hologram

There are legitimate user-facing dynamic head updates: favicons (notification badges), page-specific scripts, A/B testing scripts, page-specific widgets (chat, analytics), theme metadata (theme-color), and viewport metadata.

You could create separate layouts for pages that need different head content, but if the only difference between pages is in the <head>, it’s much cleaner to just pass those as props to a single layout component. No need to duplicate the entire layout structure.

But here’s the broader point: even if the metadata is static and only matters for initial server-side rendering, treating the layout with its head section as a single component is still clearer. No special cases, no mental overhead of “this part uses the framework’s component model, but this other part uses a separate template system” or some impeative glue. It’s just components all the way down, which significantly simplifies the mental model.

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41989 114
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement