API reference

The Python surface of spaday. The component classes themselves (WaButton, Stack, LightweightChart, …) are generated and not listed here — see Author a component tree and Generate typed classes.

Authoring

class spaday.Component(*children: Component | dict | str, key: str | None = None, props: Dict[str, Any] | None = None, **attrs: Any)[source]

Bases: object

Base for a node in the spaday component tree.

Author it two equivalent ways: nest children positionally in the constructor and set generic props as keywords — App(Nav("title"), Body(...), id="root") — or build it up fluently with .child() / .prop(). A string child becomes a text node. Subclasses set the class attribute tag and forward their typed props via props= (only the ones the author set — None means “leave the element’s own default”).

key(key: str) Component[source]

Set the reconciliation key (for keyed child diffing).

child(*nodes: Component | dict | str) Component[source]

Append one or more children to the default slot (a string child becomes a text node).

child_in(slot: str, node: Component | dict | str) Component[source]

Append a child to a named slot (a string becomes a <span> text node).

text(value: str) Component[source]

Set the element’s text content (e.g. a button or option label).

Text is set as the textContent DOM property by the runtime, so this is for leaf elements whose label is their text (don’t combine it with child nodes).

prop(name: str, value: Any) Component[source]

Set an arbitrary prop (escape hatch for attributes a typed class doesn’t expose).

style(**decls: Any) Component[source]

Set inline CSS declarations, e.g. .style(padding="1rem", font_size="2rem").

Keys are kebab-cased (font_sizefont-size; a trailing _ is dropped so reserved words work, float_float). Composes with css() and any literal style prop.

css(**variables: Any) Component[source]

Set CSS custom properties — the theming knob, e.g. .css(background_color="navy")--background-color: navy. This is how a web component’s documented –* theme tokens are set from Python (per component), and how the spa-* shell is re-themed at the app level (App().css(spa_surface="#111", spa_border="#333") cascades to the whole shell). WebAwesome’s own tokens (--wa-color-*) are set the same way. See spaday.theme.

classes(*names: str) Component[source]

Add CSS classes (component variants / theme states), e.g. .classes("wa-dark").

on(event: str, action: Any) Component[source]

Bind a declarative Action to a DOM event (e.g. "click").

The action is serialized as data and interpreted in the browser when the event fires — no round-trip to Python.

bind(prop: str, field: str, *, mode: str = 'one-way') Component[source]

Reactively bind a prop to a state field in the runtime’s signal store.

mode="one-way" keeps the prop in sync with the field; "two-way" also writes the field back when the control changes (for value-like controls). The binding is data interpreted in the browser — the field’s value flows to the prop with no round-trip to Python.

compute(prop: str, expr: Any) Component[source]

Reactively set prop to a value computed from state fields (one-way).

expr is a field expression (field() / eq / not_ / all_ / any_ / lit) evaluated in the browser against the signal store and recomputed whenever any field it reads changes, e.g. compute("disabled", not_(field("enabled"))).

bind_root_class(name: str, field: str) Component[source]

Toggle a CSS class on the document root (<html>) from a boolean reactive state field.

The escape hatch for page-level theming that lives outside the component tree — most notably WebAwesome’s wa-dark: App(...).bind_root_class("wa-dark", "dark") makes a switch bound to a dark field re-theme the whole page (the rest follows via CSS tokens; canvas widgets that can’t read a class take a .compute("theme", cond(field("dark"), "dark", "light")) instead). One-way (the field drives the class); active only when mounted with a signal Store.

to_node() dict[source]

The node as the core’s JSON-ready dict (empty fields omitted, like the Rust core).

to_json() str[source]

The node serialized for the core’s diff/apply.

spaday.element(tag: str, *children: Component | dict | str, key: str | None = None, **props: Any) Component[source]

Build a plain element (e.g. a div container) for structure a typed component doesn’t cover.

Children nest positionally; a prop name with a trailing underscore is de-escaped so reserved words work (class_class). e.g. element("div", Strong("hi"), id="root", class_="card").

Action DSL

Behavior attached to a component with Component.on; see Add behavior and reactivity.

Actions

class spaday.SetProp(target: Ref, prop: str, value: Any)[source]

Bases: Action

Set prop on target to value (an Expr or a plain literal).

class spaday.Toggle(target: Ref, prop: str)[source]

Bases: Action

Flip a boolean prop on target (e.g. hidden, checked, open).

class spaday.Sequence(*actions: Action)[source]

Bases: Action

Run several actions in order.

class spaday.Emit(event: str, detail: Any = None)[source]

Bases: Action

Dispatch a (bubbling) custom DOM event named event with an optional detail expression.

class spaday.SendPatch(model: str, field: str, value: Any)[source]

Bases: Action

Set field to value on a host-routed model (e.g. a transports model).

The runtime surfaces this as a patch intent (a bubbling spaday:patch DOM event carrying {model, field, value}); the app routes it to the actual wire. This is how a control edit is authored declaratively instead of with a hand-written transports listener.

class spaday.If(cond: Any, then: Action, els: Action | None = None)[source]

Bases: Action

Run then if cond is truthy, else els (if given) — branch on live state, e.g. If(prop(by_id("sw"), "checked"), SetProp(...), SetProp(...)).

class spaday.CallEndpoint(method: str, url: str, body: Any = None)[source]

Bases: Action

A REST round-trip: method url with an optional JSON body (an Expr or a plain value). The one intentional server call — the runtime performs it with fetch.

class spaday.NamedJs(handler: str)[source]

Bases: Action

The escape hatch: invoke a pre-registered named JS handler (no arbitrary eval). Register it on the JS side with registerHandler(name, fn); use only for the rare irreducible case.

Expressions and references

spaday.lit(value: Any) Expr[source]

A literal value.

spaday.event_value() Expr[source]

The triggering event’s value — a control’s checked (booleans) else value else detail.

spaday.not_(of: Any) Expr[source]

Boolean negation of an expression (or a literal).

spaday.prop(target: Ref, name: str) Expr[source]

The current value of a name prop on target — reads live element state, e.g. prop(by_id("sw"), "checked") for use as a condition.

spaday.field(name: str) Expr[source]

The current value of a reactive state field — for a computed binding (Component.compute), evaluated against the signal store in the browser, e.g. not_(field("enabled")).

spaday.eq(a: Any, b: Any) Expr[source]

True when two expressions are equal, e.g. eq(field("mode"), "advanced").

spaday.all_(*exprs: Any) Expr[source]

True when every expression is truthy (logical AND).

spaday.any_(*exprs: Any) Expr[source]

True when any expression is truthy (logical OR).

spaday.this() Ref[source]

The element the event fired on (the listener’s element).

spaday.by_id(id: str) Ref[source]

The element with this id within the mounted tree.

Binding helper

spaday.bind is a one-way event-driven convenience (control change → set a target prop). For reactive state bindings prefer Component.bind / Component.compute (above).

spaday.bind(source: Any, target: Ref, target_prop: str, *, transform: Any = None) Any[source]

One-way reactive binding: when source (a control component) changes, set target_prop on target (a Ref, e.g. by_id("panel")) to the source’s value — optionally passed through transform (e.g. not_()). Returns source so it composes in a tree:

bind(WaSwitch().text("Show"), by_id("panel"), "hidden", transform=not_)

Event-driven (sugar over SetProp on the source’s change); the signal-graph reactive engine and two-way binding are future work.

Validation

spaday.validate(tree: Component | dict) None[source]

Raise ValidationError if any by_id(...) reference in the tree’s actions is unresolved.

Pass a Component (or its serialized node dict). Returns None on success.

exception spaday.ValidationError[source]

Bases: ValueError

Raised by validate() when a component tree has unresolved references.

CEM binding generator

spaday.parse_cem(manifest)

Parse a custom-elements.json manifest into the JSON-encoded list of component schemas.

spaday.generate(manifest_path: str, out_path: str | None = None, *, source: str | None = None) str[source]

Render a manifest’s components into a Python module; write it to out_path if given.

spaday.classes(manifest_path: str) Dict[str, Type[Component]][source]
spaday.classes(manifest_path: str, name: str) Type[Component]

Build Component subclasses from a manifest at runtime.

The dynamic counterpart to generate(): build classes without emitting a file. With name, returns just that one class (MyClass = spaday.classes(manifest, "MyClass")); otherwise returns {class_name: class} for the whole manifest. Handy for binding an arbitrary or one-off manifest on the fly. Unlike the committed, generated catalog (e.g. spaday.components.webawesome), these classes are not statically typed — the type checker can’t see their per-attribute signatures — though they still validate keyword names at call time. Reach for generate() (committed codegen) when you want typing.

Notebook host

Core diff / apply

The low-level component-tree engine (JSON wire form), shared byte-for-byte with the browser runtime.

spaday.diff(old, new)

Diff two JSON-encoded component trees, returning the JSON-encoded patch.

Thin wrapper over the shared core (spaday::diff_json); the same code runs in the wasm binding.

spaday.apply(root, patch)

Apply a JSON-encoded patch to a JSON-encoded tree, returning the JSON-encoded result.