---
title: Composing Interfaces
sidebarTitle: Composition
description: Nesting components into layouts, layouts into cards, and cards into complete interfaces.
icon: compass-drafting
---

import { ComponentPreview } from '/snippets/component-preview.mdx'

Prefab UIs are trees of components. You compose them with Python's `with` statement: nesting in code mirrors nesting on screen. This page builds up from simple layout primitives to a complete interface, one layer at a time.

Composition controls the _structure_ of your interface, while CSS handles styling and layout fine-tuning. Every component accepts a `css_class` prop that maps directly to [Tailwind utility classes](/css), so you can adjust widths, colors, spacing, and more without leaving Python.

## Rows and columns

Every interface needs a way to arrange things on screen. Prefab provides two fundamental layout containers: `Row` arranges children horizontally, and `Column` stacks them vertically. Both accept a `gap` parameter that controls the spacing between children; the number maps to [Tailwind's spacing scale](/css), so `gap=4` means `1rem`.

To place components inside a container, use Python's `with` statement. Any component created inside a `with` block automatically becomes a child of that container.

Here's a row of three green divs:

<ComponentPreview json={{"view":{"cssClass":"gap-4","type":"Row","children":[{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBSb3cKCndpdGggUm93KGdhcD00KToKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbWQgaC0xMCB3LTI0IikKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbWQgaC0xMCB3LTI0IikKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbWQgaC0xMCB3LTI0IikK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Div, Row

with Row(gap=4):
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4",
    "type": "Row",
    "children": [
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"},
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"},
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"}
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

And here's a column. By default, a `Column` stretches to fill the available width; the `css_class="w-auto"` override shrinks it to fit its content instead.

<ComponentPreview json={{"view":{"cssClass":"gap-4 w-auto","type":"Column","children":[{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10 w-24","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBEaXYKCndpdGggQ29sdW1uKGdhcD00LCBjc3NfY2xhc3M9InctYXV0byIpOgogICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIHctMjQiKQogICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIHctMjQiKQogICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIHctMjQiKQo=">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Div

with Column(gap=4, css_class="w-auto"):
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
    Div(css_class="bg-emerald-500 rounded-md h-10 w-24")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4 w-auto",
    "type": "Column",
    "children": [
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"},
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"},
      {"cssClass": "bg-emerald-500 rounded-md h-10 w-24", "type": "Div"}
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Nesting

Containers nest inside each other, and there's no limit to how deep you can go. The structure of your Python code directly mirrors the structure of the rendered UI: each level of indentation corresponds to a level of visual nesting. This makes it easy to read code and know exactly what the output will look like.

<ComponentPreview json={{"view":{"cssClass":"gap-4 w-auto","type":"Column","children":[{"cssClass":"gap-4","type":"Row","children":[{"cssClass":"bg-blue-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-blue-500 rounded-md h-10 w-24","type":"Div"},{"cssClass":"bg-blue-500 rounded-md h-10 w-24","type":"Div"}]},{"cssClass":"bg-purple-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBEaXYsIFJvdwoKd2l0aCBDb2x1bW4oZ2FwPTQsIGNzc19jbGFzcz0idy1hdXRvIik6CiAgICB3aXRoIFJvdyhnYXA9NCk6CiAgICAgICAgRGl2KGNzc19jbGFzcz0iYmctYmx1ZS01MDAgcm91bmRlZC1tZCBoLTEwIHctMjQiKQogICAgICAgIERpdihjc3NfY2xhc3M9ImJnLWJsdWUtNTAwIHJvdW5kZWQtbWQgaC0xMCB3LTI0IikKICAgICAgICBEaXYoY3NzX2NsYXNzPSJiZy1ibHVlLTUwMCByb3VuZGVkLW1kIGgtMTAgdy0yNCIpCiAgICBEaXYoY3NzX2NsYXNzPSJiZy1wdXJwbGUtNTAwIHJvdW5kZWQtbWQgaC0xMCIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Div, Row

with Column(gap=4, css_class="w-auto"):
    with Row(gap=4):
        Div(css_class="bg-blue-500 rounded-md h-10 w-24")
        Div(css_class="bg-blue-500 rounded-md h-10 w-24")
        Div(css_class="bg-blue-500 rounded-md h-10 w-24")
    Div(css_class="bg-purple-500 rounded-md h-10")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4 w-auto",
    "type": "Column",
    "children": [
      {
        "cssClass": "gap-4",
        "type": "Row",
        "children": [
          {"cssClass": "bg-blue-500 rounded-md h-10 w-24", "type": "Div"},
          {"cssClass": "bg-blue-500 rounded-md h-10 w-24", "type": "Div"},
          {"cssClass": "bg-blue-500 rounded-md h-10 w-24", "type": "Div"}
        ]
      },
      {"cssClass": "bg-purple-500 rounded-md h-10", "type": "Div"}
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

The blue divs sit in a horizontal row because they're inside the `Row` block. The purple div sits below them because it's a direct child of the outer `Column`. Each component attaches to whichever container is currently open; the innermost `with` block wins.

This is the core idea of Prefab composition: nesting containers. Every Prefab interface, from a simple form to a full dashboard, is built by nesting components inside other components.

## Adding content

The layout patterns above work with any component. Prefab ships with a large library of prebuilt components: [typography](/components/typography), [badges](/components/badge), [progress bars](/components/progress), [inputs](/components/input), [charts](/components/bar-chart), [data tables](/components/data-table), and [many more](/playground). You can browse them all in the [Playground](/playground).

These components compose with Row and Column exactly the way the colored placeholders did. Prefab also includes layout components beyond these two, such as [Grid](/components/grid), [Dashboard](/components/dashboard), and [Pages](/components/pages), for more complex arrangements; they appear later on this page or in their own docs.

Here's the same Column and Row pattern, with real content:

<ComponentPreview json={{"view":{"cssClass":"gap-4 w-auto","type":"Column","children":[{"cssClass":"gap-3 items-center","type":"Row","children":[{"content":"API Server","type":"H3"},{"type":"Badge","label":"Healthy","variant":"success"}]},{"content":"Uptime: 99.97%","type":"Muted"},{"type":"Progress","value":99.97,"min":0,"max":100,"variant":"default"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQmFkZ2UsIENvbHVtbiwgSDMsIE11dGVkLCBQcm9ncmVzcywgUm93Cgp3aXRoIENvbHVtbihnYXA9NCwgY3NzX2NsYXNzPSJ3LWF1dG8iKToKICAgIHdpdGggUm93KGdhcD0zLCBhbGlnbj0iY2VudGVyIik6CiAgICAgICAgSDMoIkFQSSBTZXJ2ZXIiKQogICAgICAgIEJhZGdlKCJIZWFsdGh5IiwgdmFyaWFudD0ic3VjY2VzcyIpCiAgICBNdXRlZCgiVXB0aW1lOiA5OS45NyUiKQogICAgUHJvZ3Jlc3ModmFsdWU9OTkuOTcpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Badge, Column, H3, Muted, Progress, Row

with Column(gap=4, css_class="w-auto"):
    with Row(gap=3, align="center"):
        H3("API Server")
        Badge("Healthy", variant="success")
    Muted("Uptime: 99.97%")
    Progress(value=99.97)
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4 w-auto",
    "type": "Column",
    "children": [
      {
        "cssClass": "gap-3 items-center",
        "type": "Row",
        "children": [
          {"content": "API Server", "type": "H3"},
          {"type": "Badge", "label": "Healthy", "variant": "success"}
        ]
      },
      {"content": "Uptime: 99.97%", "type": "Muted"},
      {"type": "Progress", "value": 99.97, "min": 0, "max": 100, "variant": "default"}
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### Compound components

Some Prefab components are designed to be composed from sub-components. [Card](/components/card) expects `CardHeader`, `CardContent`, and `CardFooter` children. [Tabs](/components/tabs) expects `Tab` children. [Accordion](/components/accordion) expects `AccordionItem` children. The sub-components follow the same nesting model: each one opens a `with` block that collects its own children.

Cards are the most common compound component, wrapping related content in a bordered container with distinct header, content, and footer sections. The card below wraps the same status content from the previous example.

<ComponentPreview json={{"view":{"cssClass":"w-72","type":"Card","children":[{"type":"CardHeader","children":[{"cssClass":"gap-3 items-center","type":"Row","children":[{"type":"CardTitle","content":"API Server"},{"type":"Badge","label":"Healthy","variant":"success"}]}]},{"type":"CardContent","children":[{"cssClass":"gap-3","type":"Column","children":[{"content":"Uptime: 99.97%","type":"Muted"},{"type":"Progress","value":99.97,"min":0,"max":100,"variant":"default"}]}]},{"type":"CardFooter","children":[{"type":"Button","label":"View Logs","variant":"outline","size":"default","disabled":false}]}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Badge,
    Button,
    Card,
    CardContent,
    CardFooter,
    CardHeader,
    CardTitle,
    Column,
    Muted,
    Progress,
    Row,
)

with Card(css_class="w-72"):
    with CardHeader():
        with Row(gap=3, align="center"):
            CardTitle("API Server")
            Badge("Healthy", variant="success")
    with CardContent():
        with Column(gap=3):
            Muted("Uptime: 99.97%")
            Progress(value=99.97)
    with CardFooter():
        Button("View Logs", variant="outline")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "w-72",
    "type": "Card",
    "children": [
      {
        "type": "CardHeader",
        "children": [
          {
            "cssClass": "gap-3 items-center",
            "type": "Row",
            "children": [
              {"type": "CardTitle", "content": "API Server"},
              {"type": "Badge", "label": "Healthy", "variant": "success"}
            ]
          }
        ]
      },
      {
        "type": "CardContent",
        "children": [
          {
            "cssClass": "gap-3",
            "type": "Column",
            "children": [
              {"content": "Uptime: 99.97%", "type": "Muted"},
              {"type": "Progress", "value": 99.97, "min": 0, "max": 100, "variant": "default"}
            ]
          }
        ]
      },
      {
        "type": "CardFooter",
        "children": [
          {
            "type": "Button",
            "label": "View Logs",
            "variant": "outline",
            "size": "default",
            "disabled": false
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

The nesting is deeper, but the principle hasn't changed: every `with` block opens a container, and components created inside it become children.

## Grids and control flow

When you need to arrange multiple items in a uniform layout, [Grid](/components/grid) places children in equal-width columns that wrap automatically. Pass `columns=3` for a three-column grid, or use `min_column_width` for responsive layouts that adapt to the available space.

### Python loops

Since the DSL is plain Python, you can use a `for` loop to produce components from data. The loop runs once when the component tree is constructed, and the result is baked into the output: the renderer never sees the loop, just the components it produced. This works well when the data is static and known at build time.

<ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-3","type":"Grid","children":[{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"API Server"}]},{"type":"CardContent","children":[{"cssClass":"gap-2","type":"Column","children":[{"content":"99.97%","type":"Large"},{"content":"uptime","type":"Muted"},{"type":"Progress","value":99.97,"min":0,"max":100,"variant":"default"}]}]}]},{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"Worker"}]},{"type":"CardContent","children":[{"cssClass":"gap-2","type":"Column","children":[{"content":"94.2%","type":"Large"},{"content":"uptime","type":"Muted"},{"type":"Progress","value":94.2,"min":0,"max":100,"variant":"default"}]}]}]},{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"Scheduler"}]},{"type":"CardContent","children":[{"cssClass":"gap-2","type":"Column","children":[{"content":"99.8%","type":"Large"},{"content":"uptime","type":"Muted"},{"type":"Progress","value":99.8,"min":0,"max":100,"variant":"default"}]}]}]}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import (
    Card,
    CardContent,
    CardHeader,
    CardTitle,
    Column,
    Grid,
    Large,
    Muted,
    Progress,
)

services = [
    {"name": "API Server", "uptime": 99.97},
    {"name": "Worker", "uptime": 94.2},
    {"name": "Scheduler", "uptime": 99.8},
]

with Grid(columns=3, gap=4):
    for svc in services:
        with Card():
            with CardHeader():
                CardTitle(svc["name"])
            with CardContent():
                with Column(gap=2):
                    Large(f"{svc['uptime']}%")
                    Muted("uptime")
                    Progress(value=svc["uptime"])
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4 grid-cols-3",
    "type": "Grid",
    "children": [
      {
        "type": "Card",
        "children": [
          {
            "type": "CardHeader",
            "children": [{"type": "CardTitle", "content": "API Server"}]
          },
          {
            "type": "CardContent",
            "children": [
              {
                "cssClass": "gap-2",
                "type": "Column",
                "children": [
                  {"content": "99.97%", "type": "Large"},
                  {"content": "uptime", "type": "Muted"},
                  {"type": "Progress", "value": 99.97, "min": 0, "max": 100, "variant": "default"}
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Card",
        "children": [
          {"type": "CardHeader", "children": [{"type": "CardTitle", "content": "Worker"}]},
          {
            "type": "CardContent",
            "children": [
              {
                "cssClass": "gap-2",
                "type": "Column",
                "children": [
                  {"content": "94.2%", "type": "Large"},
                  {"content": "uptime", "type": "Muted"},
                  {"type": "Progress", "value": 94.2, "min": 0, "max": 100, "variant": "default"}
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Card",
        "children": [
          {
            "type": "CardHeader",
            "children": [{"type": "CardTitle", "content": "Scheduler"}]
          },
          {
            "type": "CardContent",
            "children": [
              {
                "cssClass": "gap-2",
                "type": "Column",
                "children": [
                  {"content": "99.8%", "type": "Large"},
                  {"content": "uptime", "type": "Muted"},
                  {"type": "Progress", "value": 99.8, "min": 0, "max": 100, "variant": "default"}
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

### ForEach

When the data lives in client-side state and can change dynamically, for example a list of items the user can add to or remove from, you need iteration that happens at render time. [`ForEach`](/components/foreach) takes a state key pointing to a list and renders its children once per item, re-rendering automatically whenever the list changes.

Inside a `ForEach` block, `{{ $item }}` refers to the current item (or its fields directly if the item is a dict), and `{{ $index }}` gives the zero-based position. Because `ForEach` is a component in the tree (not a Python loop that runs and disappears), the renderer knows about the iteration. If an action appends a fourth task to the list, `ForEach` renders a new row for it automatically.

<ComponentPreview json={{"view":{"cssClass":"gap-2","type":"Column","children":[{"type":"ForEach","key":"tasks","children":[{"content":"{{ $index + 1 }}. {{ $item }}","type":"Text"}]}]},"state":{"tasks":["Write docs","Fix bug","Ship feature"]}}} playground="ZnJvbSBwcmVmYWJfdWkuYXBwIGltcG9ydCBzZXRfaW5pdGlhbF9zdGF0ZQpmcm9tIHByZWZhYl91aS5jb21wb25lbnRzIGltcG9ydCBDb2x1bW4sIFRleHQKZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cy5jb250cm9sX2Zsb3cgaW1wb3J0IEZvckVhY2gKCnNldF9pbml0aWFsX3N0YXRlKHRhc2tzPVsiV3JpdGUgZG9jcyIsICJGaXggYnVnIiwgIlNoaXAgZmVhdHVyZSJdKQoKd2l0aCBDb2x1bW4oZ2FwPTIpOgogICAgd2l0aCBGb3JFYWNoKCJ0YXNrcyIpOgogICAgICAgIFRleHQoInt7ICRpbmRleCArIDEgfX0uIHt7ICRpdGVtIH19IikK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.app import set_initial_state
from prefab_ui.components import Column, Text
from prefab_ui.components.control_flow import ForEach

set_initial_state(tasks=["Write docs", "Fix bug", "Ship feature"])

with Column(gap=2):
    with ForEach("tasks"):
        Text("{{ $index + 1 }}. {{ $item }}")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-2",
    "type": "Column",
    "children": [
      {
        "type": "ForEach",
        "key": "tasks",
        "children": [{"content": "{{ $index + 1 }}. {{ $item }}", "type": "Text"}]
      }
    ]
  },
  "state": {"tasks": ["Write docs", "Fix bug", "Ship feature"]}
}
```
</CodeGroup>
</ComponentPreview>

### Conditionals

[`If`](/components/conditional), `Elif`, and `Else` provide render-time conditionals. `If` takes a boolean expression and only renders its children when the expression is truthy. Consecutive `If/Elif/Else` siblings form a single conditional chain: the renderer evaluates them in order and renders the first match; if nothing matches, the `Else` branch renders.

Change the select below to see the conditional switch between branches.

<ComponentPreview json={{"view":{"cssClass":"gap-3","type":"Column","children":[{"name":"status","type":"Select","placeholder":"Pick a status","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"healthy","label":"Healthy","selected":false,"disabled":false},{"type":"SelectOption","value":"warning","label":"Warning","selected":false,"disabled":false},{"type":"SelectOption","value":"error","label":"Error","selected":false,"disabled":false}]},{"type":"Condition","cases":[{"when":"{{ status == 'error' }}","children":[{"type":"Alert","variant":"destructive","children":[{"type":"AlertTitle","content":"System down"}]}]},{"when":"{{ status == 'warning' }}","children":[{"type":"Alert","variant":"warning","children":[{"type":"AlertTitle","content":"Degraded performance"}]}]}],"else":[{"type":"Badge","label":"All systems go","variant":"success"}]}]},"state":{"status":"healthy"}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.app import set_initial_state
from prefab_ui.components import Alert, AlertTitle, Badge, Column, Select, SelectOption
from prefab_ui.components.control_flow import Elif, Else, If
from prefab_ui.rx import Rx

set_initial_state(status="healthy")
status = Rx("status")

with Column(gap=3):
    with Select(name="status", placeholder="Pick a status"):
        SelectOption(value="healthy", label="Healthy")
        SelectOption(value="warning", label="Warning")
        SelectOption(value="error", label="Error")
    with If(status == "error"):
        with Alert(variant="destructive"):
            AlertTitle("System down")
    with Elif(status == "warning"):
        with Alert(variant="warning"):
            AlertTitle("Degraded performance")
    with Else():
        Badge("All systems go", variant="success")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3",
    "type": "Column",
    "children": [
      {
        "name": "status",
        "type": "Select",
        "placeholder": "Pick a status",
        "size": "default",
        "disabled": false,
        "required": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "healthy",
            "label": "Healthy",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "warning",
            "label": "Warning",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "error",
            "label": "Error",
            "selected": false,
            "disabled": false
          }
        ]
      },
      {
        "type": "Condition",
        "cases": [
          {
            "when": "{{ status == 'error' }}",
            "children": [
              {
                "type": "Alert",
                "variant": "destructive",
                "children": [{"type": "AlertTitle", "content": "System down"}]
              }
            ]
          },
          {
            "when": "{{ status == 'warning' }}",
            "children": [
              {
                "type": "Alert",
                "variant": "warning",
                "children": [{"type": "AlertTitle", "content": "Degraded performance"}]
              }
            ]
          }
        ],
        "else": [{"type": "Badge", "label": "All systems go", "variant": "success"}]
      }
    ]
  },
  "state": {"status": "healthy"}
}
```
</CodeGroup>
</ComponentPreview>

### Build-time vs render-time

Prefab UIs are declarative: your Python code runs once to build a component tree, then the renderer takes over. Python `for` loops and `if` statements produce a fixed result at build time. `ForEach` and `If/Elif/Else` are reactive: they live in the component tree and respond to state changes at render time. Use Python control flow for data that is fixed at build time, and use the control-flow components when the UI needs to respond to dynamic state. For any logic that needs to run after build time, use [server actions](/guides/actions).

## Forward references

Prefab's composition model is automatic: every component created inside a `with` block attaches to that container immediately. This creates a tension when you need a component's reactive value _before_ the component appears in the tree. The common trigger is the `.rx` pattern: column headers that show a row count, panels that preview a form input's value, progress bars above the slider they reflect. Any time you want to reference a component's reactive value in something that appears earlier in the layout, you need a way to create the component first without placing it.

Consider a label that displays a slider's current value, positioned _above_ the slider. You need to reference `slider.rx` to build the label, but `slider` doesn't exist yet at the point where the label is created. If you flip the order and create the slider first, it attaches to the current container and renders above the label, which is exactly what you were trying to avoid.

`defer=True` and `insert()` solve this.

### Deferred creation

Pass `defer=True` when creating a component to prevent it from attaching to any parent:

```python
from prefab_ui.components import Column, Label, Row, Slider, Text, insert

slider = Slider(value=75, defer=True)
```

The slider object exists, and you can reference `slider.rx`, build expressions from it, and pass it to other components. It just hasn't been placed anywhere in the tree yet.

### Placing deferred components

When you're ready to place the deferred component, call `insert()` inside the appropriate `with` block:

<ComponentPreview json={{"view":{"cssClass":"gap-2","type":"Column","children":[{"cssClass":"justify-between","type":"Row","children":[{"type":"Label","text":"Volume"},{"content":"{{ slider_21 | number }}%","bold":true,"type":"Text"}]},{"name":"slider_21","type":"Slider","min":0,"max":100,"value":75.0,"disabled":false}]},"state":{"slider_21":75.0}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBMYWJlbCwgUm93LCBTbGlkZXIsIFRleHQsIGluc2VydAoKdm9sdW1lID0gU2xpZGVyKHZhbHVlPTc1LCBkZWZlcj1UcnVlKQoKd2l0aCBDb2x1bW4oZ2FwPTIpOgogICAgd2l0aCBSb3coY3NzX2NsYXNzPSJqdXN0aWZ5LWJldHdlZW4iKToKICAgICAgICBMYWJlbCgiVm9sdW1lIikKICAgICAgICBUZXh0KGYie3ZvbHVtZS5yeC5udW1iZXIoKX0lIiwgYm9sZD1UcnVlKQogICAgaW5zZXJ0KHZvbHVtZSkK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Label, Row, Slider, Text, insert

volume = Slider(value=75, defer=True)

with Column(gap=2):
    with Row(css_class="justify-between"):
        Label("Volume")
        Text(f"{volume.rx.number()}%", bold=True)
    insert(volume)
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-2",
    "type": "Column",
    "children": [
      {
        "cssClass": "justify-between",
        "type": "Row",
        "children": [
          {"type": "Label", "text": "Volume"},
          {"content": "{{ slider_21 | number }}%", "bold": true, "type": "Text"}
        ]
      },
      {
        "name": "slider_21",
        "type": "Slider",
        "min": 0,
        "max": 100,
        "value": 75.0,
        "disabled": false
      }
    ]
  },
  "state": {"slider_21": 75.0}
}
```
</CodeGroup>
</ComponentPreview>

The slider is created first so `.rx` is available for the label. `defer=True` keeps it out of the tree. `insert(volume)` places it inside the `Column`, below the row, exactly where it should visually appear.

### Deferring subtrees

When you need to build an entire subtree of deferred components, where the components inside use `with` blocks to collect their own children, use `defer()` as a context manager:

```python
from prefab_ui.components import Column, Text, defer, insert

with Column() as page:
    Text("Header content")

    with defer():
        sidebar = Column()
        with sidebar:
            Text("Sidebar content")

    insert(sidebar)
```

Inside the `defer()` block, the normal auto-attachment mechanism is suspended. Components created there can still use `with` to nest children inside each other; they just won't attach to whatever container was active outside the block. When the block exits, the original attachment context resumes.

Outside of `.rx`, you rarely need forward references. If you are not referencing a component's reactive state before creating it, the normal composition model handles everything.
