ryanzidago

ryanzidago

How can I set a specific layout for a specific LiveView?

I have the following route:

  scope "/:locale", MyAppWeb do
    pipe_through :browser

    live "/", LandingPageLive, :home
    # some other routes
  end

And this in MyAppWeb:

 def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {MyAppWeb.Layouts, :app}

      on_mount MyAppWeb.SetLocale
      unquote(html_helpers())
    end
  end

This means that by default all LiveViews have the app layout.
How can I make it so that the LandingPageLive does not have the app layout (which contains a sidebar)?

Looking at the documentation, I see here that there are two ways to override the default layout:

  • live_session which I do not have
  • :layout option when mounting the LiveView.

Since I don’t have a live_session in my router, I’m going for the second option using {MyAppWeb.Layouts, :landing_page}:

defmodule MyAppWeb.LandingPageLive do
  use MyAppWeb, :live_view
  use Gettext, backend: MyAppWeb.Gettext

  @impl LiveView
  def mount(params, _session, socket) do
    socket = assign(socket, layout: {MyAppWeb.Layouts, :landing_page})
    {:ok, socket}
  end

  @impl LiveView
  def render(assigns) do
    ~H"""
    Welcome!
    """
  end
end

And I have a the following directory structure:

lib/my_app_web/
├── components
│   ├── core_components.ex
│   ├── layouts
│   │   ├── app.html.heex
│   │   ├── landing_page.html.heex
│   │   └── root.html.heex
│   ├── layouts.ex
│   └── sidebar.ex
├── live
│   ├── landing_page_live.ex

However, I get this error:

invalid value for reserved key :layout in Phoenix.Template.render/4 assigns.
:layout accepts a tuple of the form {LayoutModule, "template.extension"},
got: {ClipboardWeb.Layouts, :landing_page}

Looks like I need to pass a string:

defmodule MyAppWeb.LandingPageLive do
  use MyAppWeb, :live_view
  use Gettext, backend: MyAppWeb.Gettext

  @impl LiveView
  def mount(params, _session, socket) do
    socket = assign(socket, layout: {MyAppWeb.Layouts, "landing_page.html"})
    {:ok, socket}
  end

  @impl LiveView
  def render(assigns) do
    ~H"""
    Welcome!
    """
  end
end

Not enough:

no "landing_page.html" html template defined for ClipboardWeb.Layouts  (the module exists but does not define landing_page.html/1 nor render/2

My MyAppWeb.Layouts looks like so:

defmodule MyAppWeb.Layouts do
  @moduledoc """
  This module holds different layouts used by your application.

  See the `layouts` directory for all templates available.
  The "root" layout is a skeleton rendered as part of the
  application router. The "app" layout is set as the default
  layout on both `use MyAppWeb, :controller` and
  `use MyAppWeb, :live_view`.
  """
  use MyAppWeb, :html

  alias MyAppWeb.Sidebar

  embed_templates "layouts/*"
end

Thus I assume that it embeds all templates under the lib/my_app_web/components/layouts/.

What’s the expectation here?

Showing Posts 1 to 4

ryanzidago

ryanzidago OP

Decided to hack around by conditionally rendering the sidebar in the app layout based on the @sidebar_enabled variable that I set on a server hook:

defmodule MyAppWeb.Hooks.ConfigureLayout do
  @moduledoc """
  Module responsible for configuring the layout.
  """
  import Phoenix.Component, only: [assign: 2]

  alias MyAppWeb.LandingPageLive

  @impl true
  def on_mount(:default, _params, _session, socket) when socket.view == LandingPageLive do
    socket = assign(socket, sidebar_enabled: false)
    {:cont, socket}
  end

  def on_mount(:default, _params, _session, socket) do
    socket = assign(socket, sidebar_enabled: true)
    {:cont, socket}
  end
end

Which I then call in MyAppWeb:

 def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {MyAppWeb.Layouts, :app}

      on_mount MyAppWeb.Hooks.SetLocale
      on_mount MyAppWeb.Hooks.ConfigureLayout
      unquote(html_helpers())
    end
  end

Though feels more like a hack than a solution.

rhcarvalho

rhcarvalho

The return value from mount can also set the layout:

It must return either {:ok, socket} or {:ok, socket, options}, where options is one of:

  • :temporary_assigns - a keyword list of assigns that are temporary and must be reset to their value after every render. Note that once the value is reset, it won’t be re-rendered again until it is explicitly assigned
  • :layout - the optional layout to be used by the LiveView. Setting this option will override any layout previously set via Phoenix.LiveView.Router.live_session/2 or on use Phoenix.LiveView
LostKobrakai

LostKobrakai

This is wrong. You don’t assign the layout as an assign on the socket, but it’s an option on the return tuple of mount.

def mount(params, _session, socket) do
    {:ok, socket, layout: {MyAppWeb.Layouts, :landing_page}}
  end
ryanzidago

ryanzidago OP

Ah yeah completely on my, I now see clearly how it’s written in the documentation:

The :layout option returned on mount, via {:ok, socket, layout: ...} will override any previously set layout option

Many thanks both of you @rhcarvalho @LostKobrakai !

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
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
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews