Use spaday in a Jupyter notebook¶
This guide shows you how to render a spaday UI in a notebook and round-trip its state with Python — no server. It works in Jupyter (Lab / Notebook / Colab / VS Code) and the wider anywidget ecosystem (Marimo, Shiny-for-Python, Solara, Panel).
Install the host:
pip install "spaday[widget]"
Render a tree¶
Wrap any component tree in Widget and return it from a cell:
from spaday import Widget
from spaday.components.webawesome import WaCard, WaSwitch
Widget(WaCard().child(WaSwitch().text("Lamp")))
The full WebAwesome catalog and the spaday runtime are bundled into the widget, so wa-* components
render with nothing else to load.
Update the rendered tree¶
Keep a reference and call update to replace the tree; the browser applies a minimal diff (live
elements are preserved, not rebuilt):
w = Widget(WaCard().child(WaSwitch().text("Lamp")))
w # display it
w.update(WaCard().child(WaSwitch().text("Lamp")).child(WaSwitch().text("Fan")))
Back reactive bindings with state¶
Pass a state dict to drive the tree’s reactive bindings. A two-way-bound control
updates the state from the browser, and assigning w.state updates the control:
from spaday import Widget
from spaday.components.webawesome import WaSwitch
w = Widget(WaSwitch().text("Lamp").bind("checked", "lamp", mode="two-way"), state={"lamp": True})
w
w.state # -> {'lamp': True}; flip the switch, then re-read -> {'lamp': False}
w.state = {"lamp": True} # turns the switch back on
React to changes (including browser-driven ones) with on_state:
w.on_state(lambda state: print("state:", state))
Handle a SendPatch intent¶
A SendPatch action surfaces an intent the host forwards to Python. Register a handler
with on_intent:
w.on_intent(lambda content: print("intent:", content)) # content is {"type": "spaday:patch", "detail": {...}}
For most cases prefer a two-way binding over SendPatch + on_intent — the binding already carries the
control→state edit.
Embed in Panel¶
Because the widget is an anywidget, Panel renders it directly:
import panel as pn
pn.extension()
pn.panel(Widget(WaSwitch().text("Lamp")))