Layouts
A layout is the part of the page that stays the same from one page to the next: a header, a sidebar, a footer. It stays mounted while visits move between the pages it wraps, so its state (a scroll position, an open menu) is kept.
_layout.tsx
A _layout.tsx in a directory of app/pages/ wraps every page below it. Its default export is a component that
renders the page as children:
// app/pages/_layout.tsx: around every page
import type { ReactNode } from 'react'
export default function Layout({ children }: { children: ReactNode }) {
return (
<>
<header>…</header>
<main>{children}</main>
</>
)
}Layouts nest with the directories, outermost first:
app/pages/
├─ _layout.tsx # around every page
├─ index.tsx
└─ docs/
├─ _layout.tsx # around the docs pages, inside the one above
├─ intro.mdx
└─ routes.mdxdocs/intro is rendered inside _layout.tsx, then docs/_layout.tsx. Pages written in MDX get their
layouts the same way. Read the page and its props in a layout with Inertia's usePage().
Different layouts for different parts
A page's name is where its file is, and its URL is the route's: the two are independent. So the directories of
app/pages/ can follow the layouts rather than the URLs:
app/pages/
├─ marketing/
│ ├─ _layout.tsx # the site's header and footer
│ ├─ index.tsx # rendered by routes/index.ts at /
│ └─ legal/
│ ├─ _layout.tsx # a narrow column, inside the marketing layout
│ ├─ terms.tsx # rendered by routes/terms.ts at /terms
│ └─ privacy.tsx
└─ admin/
├─ _layout.tsx # the dashboard's sidebar
└─ users.tsxA part that should replace a layout rather than sit inside it goes in a directory beside it: pages/legal/ instead of
pages/marketing/legal/.
Code-split with their pages
A layout is in the JavaScript of its pages only: a visitor of the home page doesn't download the docs' sidebar. Fondu
does it at build time: each page imports the _layout.tsx files above it and gives them to Inertia as the page's
layout.
The app's default layout
createInertiaApp({ layout }) in app/app.tsx is Inertia's default layout: Fondu leaves it to the pages with no
_layout.tsx above them. With an app/pages/_layout.tsx, every page has one, so the default is not needed.
A page can still set its own, as Inertia allows: Page.layout = OtherLayout replaces its directories' layouts.
Files that are not pages
A file in app/pages/ whose name starts with _ is not a page: render() can't name it, and it is not in the
generated types. Besides _layout.tsx, a component used by the pages of one directory can live there too, as
_toc.tsx.