Frontend Development
Layouts
How to create and use layouts in your RedwoodSDK project
RedwoodSDK provides a powerful layout() function for creating shared UI layouts across your routes. This allows you to maintain consistent page structures, implement nested layouts, and avoid code duplication.
Key Features
- Composable: Works seamlessly with existing
prefix(),render(), androute()functions - Nested Support: Multiple
layout()calls create properly nested component hierarchies - SSR/RSC Safe: Automatic client component detection prevents serialization errors
- Middleware Friendly: Preserves middleware functions in route arrays
Example with Code
Create a layout component:
import type { LayoutProps } from 'rwsdk/router'
export function AppLayout({ children, requestInfo }: LayoutProps) {
return (
<div className="app">
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
{requestInfo && (
<span>Path: {new URL(requestInfo.request.url).pathname}</span>
)}
</header>
<main>{children}</main>
<footer>© {new Date().getFullYear()}</footer>
</div>
);
}Use the layout in your routes:
import { layout, route, render } from 'rwsdk/router'
import { AppLayout } from './layouts/AppLayout'
import HomePage from './pages/HomePage'
import AboutPage from './pages/AboutPage'
export default defineApp([
render(Document, [
layout(AppLayout, [
route("/", HomePage),
route("/about", AboutPage),
])
])
])Create nested layouts:
import type { LayoutProps } from 'rwsdk/router'
export function AdminLayout({ children }: LayoutProps) {
"use client" // Client component example
return (
<div className="admin-panel">
<aside>Admin Sidebar</aside>
<div className="admin-content">{children}</div>
</div>
);
}Combine layouts with other router functions:
export default defineApp([
render(Document, [
layout(AppLayout, [
route("/", HomePage),
prefix("/admin", [
layout(AdminLayout, [
route("/", AdminDashboard),
route("/users", UserManagement),
])
])
])
])
])Nesting Order
Layouts are applied with outer layouts first. For example:
layout(Outer, [layout(Inner, [route("/", Page)])])
// Results in: <Outer><Inner><Page /></Inner></Outer>Layout Props
Layout components receive two props:
children: The wrapped route contentrequestInfo: Request context (only passed to server components)
There's a specific type for the LayoutProps prop:
import type { LayoutProps } from 'rwsdk/router'
export function AppLayout({ children, requestInfo }: LayoutProps) {
...Client Components
The layout() function automatically detects client components and only passes requestInfo to server components to prevent serialization errors.
Complex Composition
Each of these examples work:
prefix("/api", layout(ApiLayout, routes)) // ✅
layout(AppLayout, prefix("/admin", routes)) // ✅
render(Document, layout(AppLayout, routes)) // ✅
``