Skip to content
4th April 2025: This is a preview, whilst production-ready, it means some APIs might change

Layouts

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(), and route() 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

  1. Create a layout component:

    src/app/layouts/AppLayout.tsx
    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>&copy; {new Date().getFullYear()}</footer>
    </div>
    );
    }
  2. Use the layout in your routes:

    src/app/worker.tsx
    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),
    ])
    ])
    ])
  3. Create nested layouts:

    src/app/layouts/AdminLayout.tsx
    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>
    );
    }
  4. Combine layouts with other router functions:

    src/app/worker.tsx
    export default defineApp([
    render(Document, [
    layout(AppLayout, [
    route("/", HomePage),
    prefix("/admin", [
    layout(AdminLayout, [
    route("/", AdminDashboard),
    route("/users", UserManagement),
    ])
    ])
    ])
    ])
    ])

Layout Props

Layout components receive two props:

  • children: The wrapped route content
  • requestInfo: Request context (only passed to server components)

There’s a specific type for the LayoutProps prop:

src/app/layouts/AppLayout.tsx
import type { LayoutProps } from 'rwsdk/router'
export function AppLayout({ children, requestInfo }: LayoutProps) {
...

Complex Composition

Each of these examples work:

src/app/worker.tsx
prefix("/api", layout(ApiLayout, routes)) // ✅
layout(AppLayout, prefix("/admin", routes)) // ✅
render(Document, layout(AppLayout, routes)) // ✅
``