Prefab Documentation

repository·main·Indexed 20 days ago

https://github.com/prefecthq/prefab

A generative UI framework for Python developers to build interactive, production-ready interfaces using a declarative DSL. Optimized for the Model Context Protocol (MCP) ecosystem and agentic workflows, Prefab features a library of 100+ prebuilt components, a reactive state system via the Rx class, and a React renderer. It includes a CLI for serving and exporting apps to standalone HTML, as well as support for custom JavaScript expression pipes (js_pipes).

Tokens
302.4K
Snippets
908
Records
1.1K
Agent score
68%

What's inside Prefab

  1. What is Prefab?

    main

    Prefab is a generative UI framework designed for building rich, interactive interfaces entirely in Python. It allows developers to create MCP (Model Context Protocol) Apps, data dashboards, and interactive tools using a Python DSL (Domain Specific Language).

    Key features include:

    • Component Composition: Uses a library of 100+ prebuilt components.
    • Python DSL: Employs context managers for nesting components, making it token-efficient and compatible with streaming.
    • Reactive State: A reactive state system (via the Rx class) handles client-side interactivity without requiring JavaScript.
    • React Renderer: A bundled React frontend (built on shadcn/ui) renders the component tree, which is compiled to a JSON protocol.
    • Agent-Friendly: Because the UI is declarative and serializable, it is ideal for AI agents to generate or manipulate.
  2. Explore Prefab mini examples and features

    main

    The examples/mini directory contains small, focused applications that demonstrate specific Prefab features. Use these as reference implementations for the following capabilities:

    • Reactive state with Rx: Creating live-updating text components.
    • Reactive binding: Driving multiple UI elements (like a Ring, Progress bars, and text) from a single input like a Slider.
    • Dynamic lists: Using ForEach to render lists with add/remove item functionality.
    • Conditional rendering: Using If/Else logic to render components based on a switch state.
    • Action chains: Sequencing multiple actions such as SetState, ShowToast, and ToggleState.
  3. Use @prefecthq/prefab-ui for React rendering

    main

    The @prefecthq/prefab-ui package provides a bundled React renderer designed to transform Prefab's JSON wire format into a live user interface.

    Note: This package is specifically for React environments. If you are working within a Python environment, you should use the prefab-ui Python package instead.

  4. What is Prefab and how does it work

    main

    Prefab is a transport-agnostic UI library that enables Python developers to create interactive web interfaces using a Python DSL.

    The core pipeline follows a three-step process:

    1. Python DSL: You describe the UI using Python code.
    2. JSON: The DSL is serialized into a JSON component tree.
    3. React Renderer: A client-side React application interprets the JSON and renders the interactive UI in the browser.

    This architecture allows for rich, interactive UIs without requiring the developer to write JavaScript, HTML, or manage a frontend build system.

  5. What is the $event reactive reference?

    main

    In Prefab, $event (accessed via the EVENT constant in Python) is a reactive reference to the value produced by the interaction that triggered an action handler. The data type and content of $event depend on the component that fired the event:

    Component$event value
    Input / TextareaCurrent text (string)
    SliderCurrent position (number)
    Checkbox / SwitchChecked state (boolean)
    SelectSelected value (string)
    RadioGroupSelected value (string)
    Buttonundefined
  6. How Dashboard and Grid components differ

    main

    Prefab provides two distinct grid systems depending on your layout requirements:

    • Grid: Uses an auto-flow mechanism where children are placed left-to-right and wrap to new rows automatically. Use this for most standard layouts where items have different sizes but do not require specific, pinned coordinates. You can use GridItem within a Grid to allow children to span multiple columns or rows while maintaining responsive reflow.

    • Dashboard: Uses explicit coordinate-based positioning. Each child must be a DashboardItem with defined coordinates. Use this when you need pixel-precise control or are building layouts like drag-and-drop builders where items are pinned to a canvas.

  7. Access nested state using dot-paths

    main

    State keys can use dot-notation to access nested objects or array indices:

    • Nested Objects: profile.name accesses the name field inside the profile object.
    • Arrays: todos.0.done accesses the done field of the first item in the todos array.

    When using a ForEach loop, you can target the current row's state dynamically using the {{ $index }} template expression in the component's name prop.

    from prefab_ui.components import Checkbox, Text
    from prefab_ui.components.control_flow import ForEach
    
    # Dynamically targets the 'done' field of the current item in the 'todos' array
    with ForEach("todos"):
        Checkbox(name="todos.{{ $index }}.done")
        Text("{{ $item.text }}")
  8. How state-driven UI escalation works in Prefab

    main

    In Prefab, UI transitions (often called 'escalation') are driven by a single integer in the application state. Instead of managing explicit 'screens' or 'steps', the UI is rendered as a pure function of the state value.

    Key Concepts:

    • Reactive References: Use Rx("key") to create a reactive reference to a state key. This reference is used to both branch the UI logic and advance the state.
    • Conditional Rendering: Use a conditional chain (e.g., If, Elif, Else) to define which UI elements render for specific state values. Elif behaves like Python's elif, ensuring exactly one branch renders at a time.
    • State Advancement via Actions: Use actions like SetState(key, value) within event handlers (e.g., on_click) to update the state. To create a sequence, use reactive expressions like SetState(presses, presses + 1) to increment the counter.
    • Reactive Guards: Components like Badge or text elements can be wrapped in If(condition): blocks. These blocks automatically re-evaluate and update the UI whenever the underlying state dependency changes.
    # Conceptual logic for a state-driven button escalation
    presses = Rx("presses")
    
    # The UI is a conditional chain based on the 'presses' state
    body = If(presses == 0, 
        Button("Start", on_click=SetState("presses", presses + 1)),
        Elif(presses == 1, 
            Button("Next", on_click=SetState("presses", presses + 1)),
        # ... more branches
        Else()
    )
    
    # Header reacts to state changes automatically
    header = If(presses > 0, Badge(presses))
  9. Align children in a Column

    main

    In a Column, the align property controls the horizontal (cross-axis) alignment of children. This is particularly useful when children have different widths.

    Supported values for align:

    • "start"
    • "center"
    • "end"
    • "stretch"
    • "baseline"

    Example with align="center":

    from prefab_ui.components import Column, Div
    
    with Column(gap=4, align="center", css_class="p-3 border-3 border-dashed"):
        Div(css_class="bg-emerald-500 rounded-md h-10 w-full")
        Div(css_class="bg-emerald-500 rounded-md h-10 w-3/4")
        Div(css_class="bg-emerald-500 rounded-md h-10 w-1/2")
  10. Control layering in Dashboard with z_index

    main

    When items in a Dashboard overlap (their column/row ranges intersect), they stack visually. By default, items rendered later in the code appear on top of earlier ones. To explicitly control this stacking order, use the z_index parameter on a DashboardItem. A higher z_index value will render the item on top of items with lower values.

    from prefab_ui.components import (
        Card, CardContent,
        Dashboard, DashboardItem,
        Div, Text,
    )
    
    with Dashboard(columns=6, row_height=80, gap=2):
        # This panel covers columns 1-4
        with DashboardItem(col=1, row=1, col_span=4, row_span=2):
            with Div(css_class="bg-blue-500 rounded-md h-full flex items-center justify-center"):
                Text("Background panel", css_class="text-white font-semibold")
        # This card covers columns 3-6, overlapping columns 3-4
        with DashboardItem(col=3, row=1, col_span=4, row_span=2, z_index=1):
            with Card(css_class="h-full border-2 border-amber-500"):
                with CardContent(css_class="flex items-center justify-center h-full"):
                    Text("Overlay (z_index=1)", css_class="font-semibold")
  11. Send dynamic messages using state interpolation

    main

    SendMessage supports state interpolation using the {{ key }} syntax. This allows you to capture input from a user (e.g., via an Input component) and send that specific value to the chat.

    In Python, you can pass the reactive value of an input component (e.g., input_component.rx) to SendMessage to achieve this.

    from prefab_ui.components import Input, Button, Column
    from prefab_ui.actions.mcp import SendMessage
    
    with Column(gap=3):
        question = Input(name="question", placeholder="Ask a follow-up question...")
        Button("Ask", on_click=SendMessage(question.rx))