---
title: Layout & Middleware | Guides
contributors:
  - manucorporat
  - adamdbradley
  - Oyemade
  - mhevery
  - nnelgxorz
  - saisrikardumpeti
  - mrhoodz
  - aendel
  - jemsco
  - copilot
updated_at: '2023-06-25T19:43:33Z'
created_at: '2023-03-20T23:45:13Z'
---

import { Note } from '~/components/note/note';

# Nested Layouts

Layouts provide **nested UI and request handling (middleware)** to a set of routes:

- **Shared request handling**: Accomplished by adding an `onRequest` method.
- **Shared UI**: Accomplished by `export default` a Qwik component.

## Example

Now, combine all the previously discussed concepts to build a full app.

In the proposed example, you will notice a site with 2 pages: `https://example.com` and `https://example.com/about`. The goal is to add a common header and footer to all the pages, the only difference between the pages is the content in the middle.

```
┌───────────────────────────────────────────────────┐
│ Header                                            │
├─────────┬─────────────────────────────────────────┤
│ Menu    │ <ROUTE_SPECIFIC_CONTENT>                │
│ - home  │                                         │
│ - about │                                         │
│         │                                         │
├─────────┴─────────────────────────────────────────┤
│ Footer                                            │
└───────────────────────────────────────────────────┘
```

First, create three components: `<Header>`, `<Footer>`, and `<Menu>`.

<Note>The developer could copy-paste these components manually into each page component, but that is repetitive and error-prone. Instead, use layouts to automatically reuse common parts.</Note>

### Routes directory

```bash
src/
├── components/
│   ├── header.tsx         # Header component implementation
│   ├── footer.tsx         # Footer component implementation
│   └── menu.tsx           # Menu component implementation
└── routes/
    ├── layout.tsx         # Layout implementation using: <Header>, <Footer>, and <Menu>
    ├── about/
    │   └── index.tsx      # https://example.com/about
    └── index.tsx          # https://example.com
```

### `src/routes/layout.tsx`

It will be used for all routes under the `src/routes` directory. It will render the `Header`, `Menu`, and `Footer` components, and also render the nested routes under the `Slot` component.

```tsx title="src/routes/layout.tsx"
import { component$, Slot } from '@qwik.dev/core';

export default component$(() => {
  return (
    <>
      <Header />
      <Menu />
      <Slot /> {/* <== This is where the route will be inserted */}
      <Footer />
    </>
  );
});
```

### `src/routes/index.tsx`

This is the main route for the site. It will be rendered within the `Slot` component in the `src/routes/layout.tsx` file. Even though the `Header`, `Menu`, or `Footer` components are not referenced, it will still be rendered with them.

```tsx title="src/routes/index.tsx"
import { component$ } from '@qwik.dev/core';

export default component$(() => {
  return <>Home</>;
});
```

### `src/routes/about/index.tsx`

Similar to the `src/routes/index.tsx` file, the `about` route will also be rendered within the `Slot` component in the `src/routes/layout.tsx` file. Even though the `Header`, `Menu`, or `Footer` components are not referenced, it will still be rendered with them.

```tsx title="src/routes/about/index.tsx"
import { component$ } from '@qwik.dev/core';

export default component$(() => {
  return <>About</>;
});
```

When you run the app, Qwik will render the `About` nested inside the `RootLayout`

```tsx
<RootLayout>
  <AboutPage />
</RootLayout>
```

[Here](https://qwik.dev/docs/advanced/routing/#named-layout) you can read more about advanced routing scenarios like named layout.

## Named Slots in Layouts

A layout can define multiple named [`<Slot />`](/docs/components/slots/) areas (for example a sidebar, a breadcrumb bar, or a secondary action bar). Because the Qwik City router passes each page as a single component to its parent layout, using named slots requires a special technique: the page's `default export` must be an **inline component** (a plain function) instead of a `component$`.

### Why inline components?

When the router composes layouts and pages it builds a tree like:

```tsx
<Layout>
  <Page />   {/* single component$ — creates a component boundary */}
</Layout>
```

Qwik's slot system splits the children of a component by their `q:slot` attribute *before* rendering. For a `component$` child the boundary is opaque, so `q:slot` attributes inside the page's output are invisible to the layout. An **inline component** (a plain function) has no such boundary — Qwik calls it directly and its returned JSX elements are visible to the layout's slot system.

### Example

**Layout with named slots:**

```tsx title="src/routes/layout.tsx"
import { component$, Slot } from '@builder.io/qwik';

export default component$(() => {
  return (
    <div class="layout">
      <nav>
        <Slot name="breadcrumb" />
      </nav>
      <main>
        <Slot /> {/* default slot — receives the page body */}
      </main>
      <aside>
        <Slot name="sidebar" />
      </aside>
    </div>
  );
});
```

**Page that fills named slots (inline component as default export):**

```tsx title="src/routes/index.tsx"
// Inline component — NOT component$, so no component boundary is created.
// Qwik calls this function directly and its JSX output is split across
// the layout's named slots based on the q:slot attributes.
export default () => (
  <>
    <nav q:slot="breadcrumb">Home / Products</nav>
    <aside q:slot="sidebar">
      <p>Filter by category</p>
    </aside>
    <div>
      <h1>Products</h1>
      <p>Main page content goes here.</p>
    </div>
  </>
);
```

Elements without a `q:slot` attribute go into the layout's default `<Slot />`, and elements with `q:slot="name"` go into the matching named `<Slot name="name" />`.

### Using hooks inside an inline page

Inline components cannot use Qwik hooks (`useSignal`, `useStore`, `useTask$`, etc.) directly. If your page needs reactive state, extract that part into a `component$` and render it inside the inline component:

```tsx title="src/routes/index.tsx"
import { component$, useSignal } from '@builder.io/qwik';

// component$ for the part that needs reactive state
const ProductList = component$(() => {
  const filter = useSignal('');
  return (
    <div>
      <input bind:value={filter} placeholder="Search…" />
      <p>Showing results for: {filter.value}</p>
    </div>
  );
});

// Inline component as default export — routes content to the layout slots
export default () => (
  <>
    <nav q:slot="breadcrumb">Home / Products</nav>
    <aside q:slot="sidebar">
      <p>Static sidebar content</p>
    </aside>
    <ProductList /> {/* goes into the default slot */}
  </>
);
```

> **Note:** The named-slot technique relies on inline components not creating a component boundary. Keep the inline default export as a thin routing shell and put all business logic inside `component$` children.

### Nested layouts with named slots

When there are nested layouts (an outer layout wrapping an inner layout wrapping a page), any **intermediate** layout that sits between the outer layout's named slots and the page must also be an inline component. It must render `{children}` directly inside a fragment — **not** wrapped in any HTML element — so that `q:slot` attributes propagate all the way up to the outer layout.

```
src/routes/
├── layout.tsx          ← outer layout (component$ — defines named slots)
├── products/
│   ├── layout.tsx      ← inner layout (inline — must pass {children} through a fragment)
│   └── index.tsx       ← page (inline — provides q:slot content)
```

**Outer layout** (`component$` with named slots — unchanged):

```tsx title="src/routes/layout.tsx"
import { component$, Slot } from '@builder.io/qwik';

export default component$(() => {
  return (
    <div class="layout">
      <nav><Slot name="breadcrumb" /></nav>
      <main><Slot /></main>
      <aside><Slot name="sidebar" /></aside>
    </div>
  );
});
```

**Inner layout** (inline component — passes `{children}` top-level in a fragment):

```tsx title="src/routes/products/layout.tsx"
// Inline component — renders its own content alongside {children} in a fragment.
// {children} MUST be top-level (not wrapped in any HTML element) so that
// q:slot attributes from nested pages propagate to the outer layout.
export default ({ children }: any) => (
  <>
    {/* contributes to the outer layout's "breadcrumb" slot */}
    <nav q:slot="breadcrumb">
      <a href="/">Home</a> / <a href="/products">Products</a>
    </nav>
    {children} {/* top-level — q:slot attributes inside are still visible to outer layout */}
  </>
);
```

**Page** (inline component — provides its own named-slot content):

```tsx title="src/routes/products/index.tsx"
export default () => (
  <>
    <aside q:slot="sidebar">
      <p>Category filters</p>
    </aside>
    <div>
      <h1>All Products</h1>
    </div>
  </>
);
```

When the router composes these three layers the outer layout's `splitProjectedChildren` receives a flat list of JSX nodes:

| Element | Source | Goes to |
|---|---|---|
| `<nav q:slot="breadcrumb">…` | inner layout | outer `breadcrumb` slot |
| `<aside q:slot="sidebar">…` | page | outer `sidebar` slot |
| `<div><h1>…` | page | outer default slot |

**What breaks the propagation:**

If the inner layout wraps `{children}` in an HTML element, Qwik stops flattening at that element boundary and the inner `q:slot` attributes from the page are no longer visible to the outer layout:

```tsx title="src/routes/products/layout.tsx — ❌ wrapping children hides q:slot attributes"
// WRONG — the <div> wrapper stops q:slot propagation to the outer layout
export default ({ children }: any) => (
  <div class="product-area">
    {children}  {/* q:slot attributes inside children are hidden from the outer layout */}
  </div>
)
```

You will either need to repeat the Slot structure, or move the wrapper div to the child component.
