Layouts React
Layouts live in resources/js/layouts. Two wrapper components, AppLayout and AuthLayout, pick the actual design at runtime, so pages never import a specific variant.
Layout selection flow
Setup → Layout (global default)
→ Settings → Layout (user override, not the auth layout)
→ LayoutService → shared `layout` prop
→ app.tsx picks AppLayout / AuthLayout by page name
→ AppLayout / AuthLayout render the chosen variant- An admin sets the global defaults (app layout, sidebar variant, collapsible mode, auth layout) on Setup → Layout.
- A user can override the app layout, sidebar variant and collapsible mode on Settings → Layout. The auth layout always comes from the global default.
- The backend shares the result as the
layoutprop (LayoutSettings). app.tsxassignsAuthLayouttoauth/*pages,[AppLayout, SettingsLayout]tosettings/*pages andAppLayoutto everything else (see Architecture → Overview).
Backend details are in Navigation & layouts.
App layouts
app-layout.tsx takes breadcrumbs?: BreadcrumbItem[] and renders one of two shells based on layout.app_layout:
app_layout | Component | Structure |
|---|---|---|
sidebar (default) | app/app-sidebar-layout.tsx | AppSidebar + AppSidebarHeader (breadcrumbs) + content |
header | app/app-header-layout.tsx | AppHeader top navigation (menus + breadcrumbs) + content |
Both shells mount the global ConfirmDialog. The sonner Toaster and TooltipProvider are added once for every page in app.tsx (withApp).
The sidebar shell also reads two settings:
| Setting | Values | Default |
|---|---|---|
sidebar_variant | inset, sidebar, floating | inset |
sidebar_collapsible | icon, offcanvas, none | icon |
The sidebar shows menus normally and setupMenus while the URL starts with /setup.
Settings layout. settings/layout.tsx renders the Profile / Security / Appearance / Layout sub-navigation inside the app shell. The active item is detected with useCurrentUrl().isCurrentOrParentUrl.
TIP
To add another app-wide wrapper (for example a banner), put it in both app-sidebar-layout.tsx and app-header-layout.tsx, or in withApp in app.tsx if it should also appear on auth pages.
Auth layouts
auth-layout.tsx takes title and description as translation keys (the layout translates them) and renders one of three designs based on layout.auth_layout:
auth_layout | Component | Look |
|---|---|---|
card (default) | auth/auth-card-layout.tsx | Logo above a centred card on a muted background |
simple | auth/auth-simple-layout.tsx | Logo, title and form on a plain background |
split | auth/auth-split-layout.tsx | Dark left panel with logo and app name, form on the right |
Per-page layout override
A page controls its layout through a static layout property:
| Goal | Set Page.layout to | Used by |
|---|---|---|
| Pass props to the default layout | An object: { breadcrumbs } or { title, description } | Most pages |
| Change layout props at runtime | Call setLayoutProps({...}) in an effect | two-factor-challenge.tsx, accept-invitation.tsx |
| No layout (full screen) | [] as never[] | home.tsx, auth/maintenance.tsx, auth/suspended.tsx |
| Pick a layout from props | A function returning a layout | errors/error.tsx |
Breadcrumbs on an app page (titles are translation keys, translated by breadcrumbs.tsx):
UsersIndex.layout = {
breadcrumbs: [
{ title: 'modules.common.nav.dashboard', href: dashboard() },
{ title: 'modules.user.breadcrumbs.users', href: index() },
],
};View other override examples
Title and description on an auth page:
Login.layout = {
title: 'modules.auth.login.title',
description: 'modules.auth.login.description',
};Dynamic title with setLayoutProps. two-factor-challenge.tsx swaps the title when the user switches to a recovery code. accept-invitation.tsx does the same when mode === 'user' to show the user-invitation wording.
import { setLayoutProps } from '@inertiajs/react';
useEffect(() => {
setLayoutProps({
title: authConfigContent.title,
description: authConfigContent.description,
});
}, [authConfigContent.title, authConfigContent.description]);No layout:
Home.layout = [] as never[];Layout chosen per request. The error page uses the app shell for signed-in users and the auth layout for guests:
import AppLayout from '@/layouts/app-layout';
import AuthLayout from '@/layouts/auth-layout';
ErrorPage.layout = (props: PageProps) =>
props.auth.user ? AppLayout : AuthLayout;View layouts folder
layouts/
├── app-layout.tsx # chooses app/app-sidebar-layout.tsx or app/app-header-layout.tsx
├── auth-layout.tsx # chooses auth/auth-card-layout.tsx, auth-simple-layout.tsx or auth-split-layout.tsx
├── app/
│ ├── app-sidebar-layout.tsx
│ └── app-header-layout.tsx
├── auth/
│ ├── auth-card-layout.tsx
│ ├── auth-simple-layout.tsx
│ └── auth-split-layout.tsx
└── settings/layout.tsx # Profile / Security / Appearance / Layout sub-navigation