conradfr
Hello, following this HN thread @josevalim asked me to open a thread regarding template inheritance.
I’d like to offer a basic example that would work in Twig or Django / Jinja2.
The root view, base.html.twig (which would be the layout BUT there is actually no concept of layout) is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}Default title for any page extending this template{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
The view, page1.html.twig, which would be rendered by the action:
{% extends 'base.html.twig' %}
{% block title %}Better title for this page{% endblock %}
{% block content %}
<h1>Phoenix is great</h1>
<div>I've nothing more to say</div>
{% endblock %}
But wait there’s more! What if want another page that uses the same title and adds something to the body? I present to you page2.html.twig:
{% extends 'page1.html.twig' %}
{% block content %}
{{ parent() }}
<div>Oh wait, I also like LiveView ;)</div>
{% endblock %}
So I’m at lost how I would implement that with function components?
Thanks.
Trending in Questions
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
Hello,
I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind.
However, when I launch mix phx.server, I get an error...
New
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
Hello folks!
So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
I’m working on a small exercise involving update_in/3, and I came up with this solution:
data = %{
name: "Periodic Table",
category:...
New
How Can I Optimise Compile Time Dependencies
I have been building an elixir application for about 2 years now. Many modules and files ha...
New
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #ai
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
gpopides
Your example, uses inheritance. What jose mentioned uses composition (if i understood correctly what he meant to say), which is what modern frontend frameworks use.
Something like
Instead of extending templates, the idea behind components is to seperate them in components and use the components.
(instead of Phoenix.Component you can use LiveComponent if you need stateful compoents and the usage differs a bit but the idea is the same)
spapas
Hey! I’m also coming from the HN thread
A library implementing this functionality in a functional language (clojure) is selmer : GitHub - yogthos/Selmer: A fast, Django inspired template system in Clojure. · GitHub
conradfr
Thanks for your reply @gpopides , I see your point.
I don’t think it solves every problems like the "page extends layout"solves over the “layout → content” does but I’ll try to think more in term of components I guess.
“Modern” frontend frameworks don’t exactly need the same thing as SSR because you’ll usually rely on a global state store (or some two way communication/event method) that will allow your UI to compose itself.
josevalim
Hi @conradfr!
I will break the answer in two.
For customizing the head, which is pretty much what Phoenix calls the root layout, I would use assigns:
Why assigns? It works for both regular request/response and Phoenix LiveView. For example, if you want to add dynamic scripts, metadata, etc, you can store them in assigns and render them as part of the layout.
But the root layout is pretty much that: the root layout. We still need to address the actual layout as perceived by users: a sidebar, main content, a footer, etc. And maybe you want different pages to have the same sidebar layout but with different items. For those, use function components are great. For example, you could create a function component like this:
Now, on each page, you can do this:
This is using a functionality called slots, which in a way are equivalent to blocks above. However, they are quite more powerful than template inheritance because they are actually structured data (and not only strings).
For example, the sidebar above still has a couple issues:
li,aand perhaps even iconsulinternallyWe can address this by also converting the sidebar to a component and specifying each sidebar item as a slot:
And now I can do:
Now we have started to encapsulate and compose UI functionality using structured data! Phoenix LiveView v0.18 will even take a step further by allowing you to annotate function components with the exact type of data they expect:
And then if you forget any of the attributes, you get a compilation warning.
I think this is the lesson that Surface taught us and ultimately why HEEx is a big deal: it makes us think of templates as rich data, like the JS community has been doing over the last several years, instead of just a series of string interpolations like I did with PHP back in 2004.
I will add two things:
This approach plays really well with LiveView because if you render the same function component more than once, LiveView will send its body exactly once to the client, regardless of how many times you render it.
This approach also fits nicely with Tailwind because, although your classes declarations tend to get verbose, they get encapsulated with the function components, which play nice with the fact LiveView renders them only once.
The only part that we are missing is also encapsulating the JavaScript bits within function components. I think Surface is already exploring something along these lines.
conradfr
Thanks a lot for your reply, it certainly addresses many things. I’ll try to apply that on a project.
In my mind it’s still inferior to inheritance because of exactly this “Now, on each page, you can do this:”, which I actually would not have to do or think about (once setup) with inheritance.
Let’s say I have the regular pages with no sidebar and an admin section with a sidebar and I also want to add entries in the navbar when I’m in the admin section.
Obviously it’s not like you can’t ultimately get the same results with the conventional layout → page paradigm, just that it eliminates a lot of problems and workarounds.
Maybe it’s like Tailwind (or … the Beam :D), you have to experience it to get what the fuss is all about.
josevalim
You can still compose them at arbitrary levels. Here is a pseudo-translation of your code to slots:
You still need to pick one layout at the top, but that’s the same with template inheritance. Still, slots can be more structured, and they allow at the composition to happen at any moment, not only from the template you are inheriting.
BartOtten
[shameless plug]
Assigns can work well and Phoenix ships with a helper for the title. Some others use cases can benefit from using helper libs.
Werner
By the way, there is also erlydtl, which is used at Zotonic (which also implements “extends” like Selmer).
Zotonic Inheritance
But if I understand correctly, this is not the right way, but “function components” and composition, right?
Werner
I’ve been thinking about “function components” since yesterday, but I’m still not quite sure how you could use it to make something like a plug-in system for an ecommerce system.
We are using Shopware, which uses PHP and Twig and provides a plugin system to customise Shopware.
For example, overwriting certain Twig blocks of Shopware in a super simple way
(without having to adapt the source of Shopware itself, which is important for Shopware updates).
BTW we are using Elixir now for some background parts, which is really super nice and easy
An example is this one below, which overrides two block of the product description part of the product page.
It’s a twig-File in our Plugin:
custom/plugins/HflDecoration/src/Resources/views/storefront/page/product-detail/description.html.twig
It’s really simple to use and unfortunately, I don’t yet see how this could be done with function components and composition.
rmoorman
Maybe the point of confusion revolves around the implementation strategy. While Shopware is a complete software package that one has to apparently customize using overrides, phoenix is a framework that expects that the implementer wires up things on its own (something that is taken care of in Shopware and is then made customizable through plugins/template overrides).
I guess if something like Shopware would be conceived with phoenix as a base in mind, it would be more like a mix app that provides component modules (with default layouts maybe) for you to use and wire up yourself (among many other kind of modules). If a layout does not fit, it then can be replaced with your own version.
It could also maybe give you behaviours to implement or maybe more something like a DSL as well, that has special syntax for overrides (think spark DSL from ash). Those modules could then be passed through config or options to plugs for example to let the shopwarex machinery pick it up. But it seems to me that the composing things yourself in your own application is favourable, though, as doing it that way would hide quite a lot. Phoenix is a just a framework after all and explicitly connecting stuff may be arguably more flexible.