---
title: If / Elif / Else
description: Conditionally render components based on expressions.
icon: code-branch
---

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

`If`, `Elif`, and `Else` let you conditionally render different components based on expression results. They mirror Python's own `if/elif/else` syntax and read the same way — no wrappers, no extra indentation.

## Basic Usage

The simplest case: show something only when a condition is true. Toggle the switch to see the alert appear and disappear.

<ComponentPreview json={{"view":{"cssClass":"gap-3","type":"Column","children":[{"cssClass":"gap-2 items-center","type":"Row","children":[{"name":"outOfStock","type":"Switch","checked":false,"size":"default","disabled":false,"required":false},{"content":"Out of stock","type":"Text"}]},{"type":"Condition","cases":[{"when":"{{ outOfStock }}","children":[{"type":"Alert","variant":"destructive","children":[{"type":"AlertTitle","content":"This item is unavailable"}]}]}]}]},"state":{"outOfStock":false}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Alert, AlertTitle, Column, Row, Switch, Text
from prefab_ui.components.control_flow import If
from prefab_ui.rx import Rx

outOfStock = Rx("outOfStock")

with Column(gap=3):
    with Row(gap=2, align="center"):
        Switch(name="outOfStock")
        Text("Out of stock")
    with If(outOfStock):
        with Alert(variant="destructive"):
            AlertTitle("This item is unavailable")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3",
    "type": "Column",
    "children": [
      {
        "cssClass": "gap-2 items-center",
        "type": "Row",
        "children": [
          {
            "name": "outOfStock",
            "type": "Switch",
            "checked": false,
            "size": "default",
            "disabled": false,
            "required": false
          },
          {"content": "Out of stock", "type": "Text"}
        ]
      },
      {
        "type": "Condition",
        "cases": [
          {
            "when": "{{ outOfStock }}",
            "children": [
              {
                "type": "Alert",
                "variant": "destructive",
                "children": [{"type": "AlertTitle", "content": "This item is unavailable"}]
              }
            ]
          }
        ]
      }
    ]
  },
  "state": {"outOfStock": false}
}
```
</CodeGroup>
</ComponentPreview>

A lone `If` renders its children when the condition is truthy, and renders nothing when it's falsy.

## If / Else

Add an `Else` branch to render fallback content when the condition is false. Toggle the switch to see the two branches swap.

<ComponentPreview json={{"view":{"cssClass":"gap-3","type":"Column","children":[{"cssClass":"gap-2 items-center","type":"Row","children":[{"name":"showDetails","type":"Switch","checked":false,"size":"default","disabled":false,"required":false},{"content":"Show details","type":"Text"}]},{"type":"Condition","cases":[{"when":"{{ showDetails }}","children":[{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"Project Details"}]},{"type":"CardContent","children":[{"content":"Heart of Gold \u2014 Infinite Improbability Drive","type":"Text"}]}]}]}],"else":[{"type":"Badge","label":"Details hidden","variant":"secondary"}]}]},"state":{"showDetails":true}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.app import set_initial_state
from prefab_ui.components import (
    Badge,
    Card,
    CardContent,
    CardHeader,
    CardTitle,
    Column,
    Row,
    Switch,
    Text,
)
from prefab_ui.components.control_flow import Else, If

state = set_initial_state(showDetails=True)

with Column(gap=3):
    with Row(gap=2, align="center"):
        Switch(name="showDetails")
        Text("Show details")
    with If(state.showDetails):
        with Card():
            with CardHeader():
                CardTitle("Project Details")
            with CardContent():
                Text("Heart of Gold — Infinite Improbability Drive")
    with Else():
        Badge("Details hidden", variant="secondary")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3",
    "type": "Column",
    "children": [
      {
        "cssClass": "gap-2 items-center",
        "type": "Row",
        "children": [
          {
            "name": "showDetails",
            "type": "Switch",
            "checked": false,
            "size": "default",
            "disabled": false,
            "required": false
          },
          {"content": "Show details", "type": "Text"}
        ]
      },
      {
        "type": "Condition",
        "cases": [
          {
            "when": "{{ showDetails }}",
            "children": [
              {
                "type": "Card",
                "children": [
                  {
                    "type": "CardHeader",
                    "children": [{"type": "CardTitle", "content": "Project Details"}]
                  },
                  {
                    "type": "CardContent",
                    "children": [
                      {"content": "Heart of Gold \u2014 Infinite Improbability Drive", "type": "Text"}
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "else": [{"type": "Badge", "label": "Details hidden", "variant": "secondary"}]
      }
    ]
  },
  "state": {"showDetails": true}
}
```
</CodeGroup>
</ComponentPreview>

## If / Elif / Else

Chain multiple conditions with `Elif`. The renderer evaluates them in order and renders the first match. If nothing matches, the `Else` branch renders. Use the select below to change the status and watch the right badge appear.

<ComponentPreview json={{"view":{"cssClass":"gap-3","type":"Column","children":[{"name":"status","type":"Select","placeholder":"Choose a status...","size":"default","disabled":false,"required":false,"invalid":false,"children":[{"type":"SelectOption","value":"active","label":"Active","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":"SelectOption","value":"other","label":"Something else","selected":false,"disabled":false}]},{"type":"Condition","cases":[{"when":"{{ status == 'error' }}","children":[{"type":"Badge","label":"Error \u2014 system down","variant":"destructive"}]},{"when":"{{ status == 'warning' }}","children":[{"type":"Badge","label":"Warning \u2014 degraded","variant":"warning"}]},{"when":"{{ status == 'active' }}","children":[{"type":"Badge","label":"Active \u2014 all systems go","variant":"success"}]}],"else":[{"type":"Badge","label":"Unknown status: {{ status }}","variant":"secondary"}]}]},"state":{"status":"active"}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.app import set_initial_state
from prefab_ui.components import (
    Badge,
    Column,
    Select,
    SelectOption,
)
from prefab_ui.components.control_flow import Elif, Else, If

state = set_initial_state(status="active")

with Column(gap=3):
    with Select(name="status", placeholder="Choose a status..."):
        SelectOption("Active", value="active")
        SelectOption("Warning", value="warning")
        SelectOption("Error", value="error")
        SelectOption("Something else", value="other")
    with If(state.status == "error"):
        Badge("Error — system down", variant="destructive")
    with Elif(state.status == "warning"):
        Badge("Warning — degraded", variant="warning")
    with Elif(state.status == "active"):
        Badge("Active — all systems go", variant="success")
    with Else():
        Badge(f"Unknown status: {state.status}", variant="secondary")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-3",
    "type": "Column",
    "children": [
      {
        "name": "status",
        "type": "Select",
        "placeholder": "Choose a status...",
        "size": "default",
        "disabled": false,
        "required": false,
        "invalid": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "active",
            "label": "Active",
            "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": "SelectOption",
            "value": "other",
            "label": "Something else",
            "selected": false,
            "disabled": false
          }
        ]
      },
      {
        "type": "Condition",
        "cases": [
          {
            "when": "{{ status == 'error' }}",
            "children": [
              {"type": "Badge", "label": "Error \u2014 system down", "variant": "destructive"}
            ]
          },
          {
            "when": "{{ status == 'warning' }}",
            "children": [{"type": "Badge", "label": "Warning \u2014 degraded", "variant": "warning"}]
          },
          {
            "when": "{{ status == 'active' }}",
            "children": [
              {"type": "Badge", "label": "Active \u2014 all systems go", "variant": "success"}
            ]
          }
        ],
        "else": [
          {
            "type": "Badge",
            "label": "Unknown status: {{ status }}",
            "variant": "secondary"
          }
        ]
      }
    ]
  },
  "state": {"status": "active"}
}
```
</CodeGroup>
</ComponentPreview>

Select "Error" or "Something else" to see different branches render. The `Else` catches anything that doesn't match the explicit conditions.

## Conditions Are Expressions

The first argument to `If` and `Elif` is a [reactive expression](/expressions/overview). With `Rx`, you can use Python operators directly:

```python
from prefab_ui.rx import Rx

status = Rx("status")
count = Rx("count")
items = Rx("items")

with If(status == "active"):
    ...

with If((count > 0) & items.length()):
    ...
```

Any expression the language supports — comparisons, boolean logic, [pipes](/expressions/pipes) — works as a condition.

## Chain Rules

Consecutive `If/Elif/Else` siblings in the same parent form a single conditional chain:

- A chain starts with `If` and extends through consecutive `Elif` and `Else` siblings
- `Elif` and `Else` are optional — a lone `If` is valid
- `Else` must be last in a chain
- Any non-conditional sibling breaks the chain — including another `If`, which starts a new independent chain

```python
from prefab_ui.rx import Rx

status = Rx("status")
showDetails = Rx("showDetails")
showFooter = Rx("showFooter")

with Column():
    # Chain 1: If / Elif / Else → one Condition node
    with If(status == "error"):
        Badge("Error", variant="destructive")
    with Elif(status == "warning"):
        Badge("Warning", variant="secondary")
    with Else():
        Badge("OK")

    Text("---")  # breaks the chain

    # Chain 2: standalone If → separate Condition node
    with If(showDetails):
        Text("Details here...")

    # Chain 3: another If starts a new chain (not an Elif!)
    with If(showFooter):
        Text("Footer content")
```

This produces three independent `Condition` nodes with a `Text` between the first and second.

## Wire Format

In the Python DSL, you write natural `If/Elif/Else` siblings. During serialization, these are grouped into a single `Condition` node on the wire. The `If` and `Elif` components never appear in the JSON directly — they're purely authoring constructs.

Each `Elif` becomes a `case` entry with a `when` expression. The `Else` branch becomes the `else` field. See the [Condition protocol reference](/protocol/condition) for the full schema.

## API Reference

<Card icon="code" title="If">
<ParamField body="condition" type="str" required>
  Expression to evaluate. Renders children when truthy. Can be passed as a positional argument.
</ParamField>
</Card>

<Card icon="code" title="Elif">
<ParamField body="condition" type="str" required>
  Expression to evaluate. Must follow an `If` or another `Elif`. Can be passed as a positional argument.
</ParamField>
</Card>

<Card icon="code" title="Else">
  Renders children when no preceding `If` or `Elif` matched. Takes no condition argument.
</Card>

## Protocol Reference

For the wire format schema, see the [Condition protocol definition](/protocol/condition).
