Phoenix: applying different layouts for different routes in LiveView
Today I needed to different layouts for public-facing and authorised pages in a LiveView app.
After an annoying amount of digging in documentation and forums, the following was the most elegant solution I found.
Assume we have these layouts in myapp/lib/myapp_web/components/layouts/
:
authenticated.html.heex
public.html.heex
And, also assuming that there is something different in each layout: stuff you can't use unless signed in.
In lib/myapp_web/router.ex
modify these authentication routes to add a layout:
in the live_session
statements:
scope "/", MyappWeb do
pipe_through [:browser, :redirect_if_user_is_authenticated]
live_session :redirect_if_user_is_authenticated,
on_mount: [{MyappWeb.UserAuth, :redirect_if_user_is_authenticated}],
layout: {MyappWeb.Layouts, :public} do
live "/users/register", UserRegistrationLive, :new
live "/users/log_in", UserLoginLive, :new
live "/users/reset_password", UserForgotPasswordLive, :new
live "/users/reset_password/:token", UserResetPasswordLive, :edit
end
post "/users/log_in", UserSessionController, :create
end
scope "/", ReflectalWeb do
pipe_through [:browser, :require_authenticated_user]
live_session :require_authenticated_user,
on_mount: [{MyappWeb.UserAuth, :ensure_authenticated}],
layout: {MyappWeb.Layouts, :authenticated} do
live "/dashboard", DashboardLive.Show, :show
live "/users/settings", UserSettingsLive, :edit
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
end
end
The important lines here are:
layout: {MyappWeb.Layouts, :public} do
and
layout: {MyappWeb.Layouts, :authenticated} do
Simple!