Skip to content

Toolbar System

PyWry provides 18 declarative Pydantic components for building interactive toolbars — no HTML or JavaScript required. This guide walks through how to create toolbars, handle events, and manage component state programmatically.

For individual component APIs, see the Components section. For event payloads, see the Event Reference.

Creating a Toolbar

A Toolbar wraps a list of components and attaches to a layout position. Pass it to any show*() method via the toolbars parameter:

from pywry import PyWry, Toolbar, Button, Select, Option

app = PyWry()

def on_save(data, event_type, label):
    app.emit("pywry:alert", {"message": "Saved!", "type": "success"}, label)

toolbar = Toolbar(
    position="top",
    items=[
        Button(label="Save", event="app:save"),
        Select(
            label="Theme",
            event="app:theme",
            options=[Option(label="Light", value="light"), Option(label="Dark", value="dark")],
            selected="dark"
        ),
    ],
)

def on_theme(data, event_type, label):
    app.emit("pywry:update-theme", {"theme": data["value"]}, label)

app.show("<h1>Hello</h1>", toolbars=[toolbar], callbacks={"app:save": on_save, "app:theme": on_theme})

Each component has an event parameter — when the user interacts with it, PyWry emits that event with a payload specific to the component type (e.g., {value: "dark"} for a Select).

sequenceDiagram
    participant User
    participant Component as Toolbar Component
    participant JS as Frontend (JS)
    participant PY as Python Callback

    User->>Component: Interact (click, type, select)
    Component->>JS: Dispatch custom event
    JS->>PY: Send via WebSocket / traitlet
    Note right of PY: Execute callback function
    PY->>JS: widget.emit(event, data)
    JS->>Component: Update component state

Layout Positions

Toolbars can be placed at 7 positions around the content area:

HEADER
LEFT
TOP
CONTENT
INSIDE
BOTTOM
RIGHT
Position Placement
header Above everything
footer Below everything
top Above content, below header
bottom Below content, above footer
left Left of content (vertical)
right Right of content (vertical)
inside Overlaid on content

You can use multiple toolbars at different positions simultaneously:

app.show(
    "<h1>Dashboard</h1>",
    toolbars=[
        Toolbar(position="header", items=[Button(label="Home", event="nav:home")]),
        Toolbar(position="top", items=[Select(event="app:filter", options=[...])]),
        Toolbar(position="footer", items=[Button(label="Export", event="app:export")]),
    ],
    callbacks={...},
)

State Management

PyWry lets you read and update toolbar component values from Python at any time.

Setting Component Values

Use toolbar:set-value to update a specific component. Assign a component_id when creating the component so you can target it later:

from pywry import PyWry, Toolbar, Select, NumberInput, Toggle, Button

app = PyWry()

def on_reset(data, event_type, label):
    # Set a single component's value
    app.emit("toolbar:set-value", {"componentId": "theme-select", "value": "light"}, label)

    # Set multiple components at once
    app.emit("toolbar:set-values", {
        "values": {
            "theme-select": "light",
            "zoom-input": 100,
            "dark-toggle": False,
        }
    }, label)

def on_theme_change(data, event_type, label):
    # Disable a button while processing
    app.emit("toolbar:set-value", {
        "componentId": "submit-btn",
        "label": "Applying...",
        "disabled": True,
    }, label)

    # Re-enable when done
    app.emit("toolbar:set-value", {
        "componentId": "submit-btn",
        "label": "Apply",
        "disabled": False,
    }, label)

app.show(
    "<h1>Settings</h1>",
    toolbars=[
        Toolbar(
            position="top",
            items=[
                Select(event="app:theme", component_id="theme-select",
                       options=[{"label": "Light", "value": "light"}, {"label": "Dark", "value": "dark"}],
                       selected="dark"),
                NumberInput(event="app:zoom", component_id="zoom-input", value=150, min=50, max=200),
                Toggle(event="app:dark", component_id="dark-toggle", value=True),
                Button(label="Reset", event="app:reset"),
            ]
        )
    ],
    callbacks={"app:reset": on_reset, "app:theme": on_theme_change},
)

Beyond value, you can set label, disabled, variant, options, style, className, placeholder, min, max, step, and more. See the Event Reference for the full attribute list.

Querying Current State

Request the current state of all toolbar components:

def on_state(data, event_type, label):
    for component_id, info in data.get("components", {}).items():
        value = info.get("value")
        app.emit("pywry:alert", {"message": f"{component_id}: {value}"}, label)

handle = app.show(
    "<h1>Hello</h1>",
    toolbars=[toolbar],
    callbacks={"toolbar:state-response": on_state},
)

# Request state
handle.emit("toolbar:request-state", {})

The response includes the full component tree:

{
    "toolbars": {"toolbar-a1b2c3d4": {"position": "top", "components": ["button-x1y2z3"]}},
    "components": {"button-x1y2z3": {"type": "button", "value": None}},
    "timestamp": 1234567890
}

Python Helper Methods

The ToolbarStateMixin (inherited by PyWry, InlineWidget, and all widget classes) provides convenience methods:

# Set a single value (with optional extra attributes)
handle.set_toolbar_value("theme-select", "light")
handle.set_toolbar_value("submit-btn", disabled=True, label="Loading...")

# Set multiple values at once
handle.set_toolbar_values({"theme-select": "light", "zoom-input": 100})

# Request state
handle.request_toolbar_state()

Next Steps

See Components for full API reference.