Generate typed classes from a manifest

spaday’s typed component classes are generated from a Custom Elements Manifest (custom-elements.json) — the standard description web-component libraries publish. This guide shows you how to generate classes for any such library. (For a library that is not a web component, see Wrap an imperative library.)

Generate a committed module

For typed classes you check into your project, use the spaday-cem CLI or spaday.generate:

spaday-cem path/to/custom-elements.json -o my_components.py
import spaday

code = spaday.generate("custom-elements.json")   # returns the module source (typed classes)

Peer packages use this workflow for committed catalogs. For example, spaday-webawesome generates spaday_webawesome/components.py from its committed manifest and checks AST drift in its test suite. Generated classes expose their normalized CEM metadata through Component.schema, ready for inclusion in a ComponentPackage catalog.

A manifest describes two kinds of input, and the schema carries both. schema.props are the element’s attributes — each one becomes a typed keyword argument. schema.fields are its property-only inputs: public fields the element declares with no attribute of their own, which is where a data component keeps its payload (an object no attribute can express). A field is set exactly like a prop — Chart(data={...}) — and the runtime writes the property; it is not a typed parameter, because a manifest’s members describe the element’s whole class surface, so only what survives filtering (methods, private and static members, inherited and attribute-backed fields, element references and callbacks are all dropped) is carried. Both kinds accept the snake_case spelling and both are checked by spaday.validate.

A json prop or field also carries type_text, the manifest’s declared type — { rows: string[]; … }, SeriesPoint[], HeatmapData. It is kept only for that kind, since string, boolean, number and enum already describe their own shape, and it is what lets a wrong payload shape be caught before the browser (see strict components).

Build classes at runtime

For a one-off or experimental manifest, spaday.classes builds the classes in memory instead — no file and no static types, but the same Component.schema, so spaday.validate checks keyword names on the built tree either way:

import spaday

ns = spaday.classes("custom-elements.json")                    # {"WaSwitch": <class>, ...}
WaSwitch = spaday.classes("custom-elements.json", "WaSwitch")  # or one class by name
WaSwitch(checked=True).to_node()

Runtime-generated classes expose the same Component.schema metadata as committed classes.

One manifest, both bindings

The parse that produces the Python classes (spaday.parse_cem(), in the Rust core) also drives the JavaScript runtime’s registry — how each prop is set, which events to bind, the slot names. So a single manifest yields both the typed Python authoring API and the browser binding, with no chance of the two disagreeing.