Skip to main content

Documentation Index

Fetch the complete documentation index at: https://prefab.prefect.io/docs/llms.txt

Use this file to discover all available pages before exploring further.

Every Prefab UI is wrapped in a PrefabApp. It holds your component tree, state, theme, and external assets together as a single unit.

Creating an App

Context manager

The natural way to build an app. Components inside the with block become the view:
from prefab_ui.app import PrefabApp
from prefab_ui.components import Heading, Slider, Text
from prefab_ui.themes import Presentation

with PrefabApp(state={"volume": 75}, theme=Presentation(accent="blue")) as app:
    Heading("Dashboard")
    slider = Slider(value=75, name="volume")
    Text(f"Volume: {slider.rx}%")
The context manager creates an implicit root Column, so children stack vertically. State, theme, and styling are declared upfront — by the time the first component renders, the app envelope is established. The root Column gets a pf-app-root CSS class that themes target for default padding. Add your own classes via css_class:
with PrefabApp(css_class="max-w-3xl mx-auto") as app:
    Heading("Centered and constrained")

Passing a view

If you build the tree separately, pass it via view=:
with Column(css_class="p-6") as view:
    Heading("Hello")

app = PrefabApp(view=view, state={"greeting": "Hello"})

From wire data

PrefabApp.from_json() wraps pre-serialized wire protocol data, for example from sandboxed execution. Keyword arguments override values from the wire:
wire = await sandbox.run(code)
app = PrefabApp.from_json(wire, state={"extra": "value"})

Fields

FieldTypeDescription
viewComponent | dictComponent tree to render (set automatically in context manager mode)
statedictInitial client-side state
themeThemeTheme to apply — see Themes
css_classstrAdditional CSS/Tailwind classes for the root container. Stacks on top of pf-app-root.
defslist[Define]Reusable component definitions
stylesheetslist[str]CSS URLs or inline CSS to load in <head>
scriptslist[str]External JS URLs to load in <head>
connect_domainslist[str]Domains to allow in CSP connect-src (for Fetch actions)
on_mountAction | list[Action]Action(s) to run when the app loads
key_bindingsdict[str, Action]Keyboard shortcuts mapping key names to actions
titlestrHTML page title (default: "Prefab")

Methods

app.html() returns a complete, self-contained HTML page with the Prefab renderer and all data baked in. app.to_json() returns the wire-format envelope — a dict with $prefab, view, state, defs, and theme. app.csp() computes Content Security Policy domains from the app’s asset configuration.

State

state sets the initial values that template expressions like {{ count }} resolve against:
with PrefabApp(state={"count": 0, "items": []}) as app:
    Text("Count: {{ count }}")
Pass state directly to the PrefabApp constructor:
with PrefabApp(state={"count": 0, "items": []}) as app:
    Text("Count: {{ count }}")

on_mount

Run actions when the app loads. This is the place to start polling intervals, fetch initial data, or perform any setup that depends on the renderer being ready:
from prefab_ui.actions import SetState
from prefab_ui.actions.mcp import CallTool
from prefab_ui.actions.timing import SetInterval
from prefab_ui.rx import RESULT

with PrefabApp(
    state={"stats": {}},
    on_mount=SetInterval(
        duration=3000,
        on_tick=CallTool(
            "get_stats",
            on_success=SetState("stats", RESULT),
        ),
    ),
) as app:
    Metric(label="CPU", value=STATE.stats.cpu + "%")
on_mount is actually a universal component property — every component supports it, not just PrefabApp. For most components it fires immediately since the entire tree renders at once. But for components inside Condition, Pages, or ForEach, it fires when they actually enter the DOM — useful for lazy data loading when a tab activates or a conditional branch becomes true.

Keyboard Shortcuts

key_bindings maps keyboard shortcuts to actions. When a user presses a matching key combination, the action fires, same as on_click or on_mount. Keys are standard DOM KeyboardEvent.key values, with optional modifier prefixes:
from prefab_ui.actions import SetState, ShowToast
from prefab_ui.rx import Rx

slide = Rx("slide")

with PrefabApp(
    state={"slide": 0},
    key_bindings={
        "ArrowRight": SetState("slide", slide + 1),
        "ArrowLeft": SetState("slide", slide - 1),
        "Shift+?": ShowToast("Help!"),
    },
) as app:
    ...
Modifier prefixes are Ctrl+, Shift+, Alt+, and Meta+ (⌘ on Mac). They combine naturally: "Ctrl+Shift+S" matches Ctrl+Shift+S. The key portion uses the standard KeyboardEvent.key names: ArrowRight, ArrowLeft, Enter, Escape, Tab, letter keys, etc. Key bindings are suppressed when the user is typing in an input, textarea, or select, so shortcuts never interfere with form entry.

Keyboard Shortcuts Dialog

The KeyboardShortcutsDialog helper builds a dialog that lists your shortcuts with styled Kbd key indicators. It returns a SetState action you can wire directly into key_bindings:
from prefab_ui.shortcuts import KeyboardShortcutsDialog

help_action = KeyboardShortcutsDialog({
    "ArrowRight": "Next slide",
    "ArrowLeft": "Previous slide",
    "Shift+?": "Show shortcuts",
})

with PrefabApp(
    key_bindings={
        "ArrowRight": SetState("slide", slide + 1),
        "ArrowLeft": SetState("slide", slide - 1),
        "Shift+?": help_action,
    },
) as app:
    ...
    # Place the dialog trigger somewhere in your layout
    KeyboardShortcutsDialog({
        "ArrowRight": "Next slide",
        "ArrowLeft": "Previous slide",
        "Shift+?": "Show shortcuts",
    })
The dialog binds its open state to a state variable (default _show_shortcuts), so the SetState action from key_bindings opens it programmatically. The trigger button also works for mouse users. No initial state setup is needed; the dialog defaults to closed. The helper uses the state-controlled Dialog name prop under the hood.

Stylesheets

The stylesheets field accepts both URLs and inline CSS. URLs become <link> tags; inline CSS (detected by {) becomes a <style> tag. For theming, prefer theme= over inline stylesheets.