---
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":[{"let":{"_loop_8":"{{ $item }}","_loop_8_idx":"{{ $index }}"},"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": [
      {
        "let": {"_loop_8": "{{ $item }}", "_loop_8_idx": "{{ $index }}"},
        "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

state = set_initial_state(status="healthy")

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(state.status == "error"):
        with Alert(variant="destructive"):
            AlertTitle("System down")
    with Elif(state.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

Sometimes you need a component's reactive value before that component exists. Python executes top-to-bottom, so if a label above a slider needs `slider.rx`, you have a problem — the slider hasn't been created at the point where the label is defined. Prefab offers two escape hatches: lambda Rx for reactive values, and defer/insert for structural rearrangement.

### Lambda Rx

The common case is needing a component's `.rx` before it's created. Wrap the reference in a lambda, and Rx defers resolution until render time:

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

vol = Rx(lambda: volume)

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

`Rx(lambda: volume)` doesn't resolve right away — it captures the *name* `volume` and waits. When the lambda returns a stateful component, Rx extracts its `.rx` automatically, so `Rx(lambda: volume)` and `Rx(lambda: volume.rx)` are equivalent. Operations like `/ 100` and `.percent()` compose lazily too, so you can build entire expression chains against a component that doesn't exist yet.

### Structural rearrangement with defer/insert

Lambda Rx covers the common case of forward-referencing a value. Occasionally you need something different: building an entire component subtree outside the current tree and grafting it in later. That's what `defer()` and `insert()` are for:

```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 a `defer()` block, auto-attachment is suspended — components can still nest children inside each other with `with`, they just won't attach to the outer container. `insert()` grafts them in where you want them.

Most of the time you won't need `defer`/`insert`. Lambda Rx covers the `.rx` forward-reference pattern, and normal composition handles everything else.
