You ship the first marketing page for your SaaS and immediately notice the problem: the public landing page now has the signed-in app nav with broken links. The login page has a "log out" button. Everything is technically rendering, but the chrome is wrong everywhere except the dashboard. The default Phoenix single root layout was never going to handle this gracefully.
This feature splits the layout into three purpose-built modules so each kind of page gets exactly the chrome it should have. The shared building blocks — logo, avatar, theme toggle — are extracted and reused, so the visual identity stays consistent even though the structure differs.
One layout per audience, not one layout for everyone
A SaaS has at least three different reading contexts: signed-in product pages, authentication flows, and public marketing or docs pages. They have different navs, different footers, and different conversion goals. Trying to handle all three in a single root layout forces conditional rendering that gets brittle quickly. Splitting them is a one-time cost that keeps every future page simple.
What This Feature Adds
lib/my_app_web/components/layouts/app.ex— main signed-in layout with full navigation, theme toggle, avatar, and flashlib/my_app_web/components/layouts/session.ex— minimal layout forphx.gen.authlogin, registration, and reset pages (no app nav)lib/my_app_web/components/layouts/public.ex— public-facing layout for marketing, docs, and other unauthenticated pages- A refactored
lib/my_app_web/components/layouts.exthat delegates to the three modules - Updated
phx.gen.authLiveViews so they useLayouts.Session.pageinstead of the default layout - Shared logo and avatar components extracted so the three layouts stay visually consistent
How It Fits Into Your Phoenix Application
Once installed, each LiveView and controller declares the layout it wants explicitly:
<Layouts.App.page flash={@flash} current_scope={@current_scope}>
<div class="space-y-6">
<!-- product content -->
</div>
</Layouts.App.page>
The Session layout is automatically used by the generated auth LiveViews; the Public layout is intended for marketing pages, the /waitlist page, and any other unauthenticated content. The theme toggle continues to work across all three layouts because it is implemented in shared components.
Installation Notes
- No hard feature dependencies, but
layoutsis itself a dependency foradmin,notifications, and (through the locale picker) several other features. Install it early in the order. - The feature rewrites generated auth LiveViews to use the session layout. If you've already customised those LiveViews, expect to merge the changes.
- The
Layouts.Public.pagecomponent is intentionally minimal. Customise it for your landing page — fonts, hero typography, footer.
Build This With Live SaaS Kit
Install saas_kit, then mix saaskit.feature.install layouts to stop forcing one root layout to do three different jobs.