Skip to content

Package

wybthon (package)

wybthon

Wybthon: a client-side Python SPA framework powered by Pyodide.

Wybthon brings a SolidJS-inspired, signals-first reactive model to the browser using Python. Component bodies run once at mount; reactivity flows through reactive holes: zero-arg getters embedded in the VNode tree that update only the DOM nodes that depend on them.

The package detects its environment at import time:

  • In a browser (Pyodide), the full surface is available, including DOM helpers, reconciler, router, events, error boundaries, suspense, portals, and the HTML element factories.
  • Outside a browser, the pure-Python surface (reactivity, VDOM data structures, forms, context, flow control, stores) remains importable so unit tests and tooling can run anywhere CPython runs.
Example

A minimal counter component::

from wybthon import button, component, create_signal, div, p, span

@component
def Counter(initial: int = 0):
    count, set_count = create_signal(initial)
    return div(
        p("Count: ", span(count)),
        button("+1", on_click=lambda e: set_count(count() + 1)),
    )
See Also

Modules:

Name Description
component

@component decorator and forward_ref for function components.

context

Context system for passing values through the component tree.

dev

Simple threaded dev server with live-reload via Server-Sent Events.

dom

Lightweight DOM wrapper utilities for Pyodide/browser environments.

error_boundary

ErrorBoundary component for catching render errors in subtrees.

events

Delegated event handling for the batched renderer.

flow

SolidJS-style reactive flow control components.

forms

Form state, validation helpers, and accessibility attribute utilities.

html

Pythonic HTML element helpers that wrap h().

kernel

Batched DOM command buffer and rendering backends.

lazy

Lazy-loaded components integrated with Suspense.

portal

Portal component for rendering children into a different DOM container.

props

DOM property application and diffing for element VNodes.

reactivity

Signal-based reactive primitives with an ownership tree.

reconciler

Reconciliation engine: mounting, patching, and unmounting VNode trees.

router

Client-side router components and navigation helpers for Pyodide apps.

router_core

Core, browser-agnostic path matching and route resolution helpers.

store

Reactive stores for nested state, inspired by SolidJS createStore.

suspense

Suspense and SuspenseList for rendering fallback UI during async loading.

template

Template-based mounting: static HTML serialization plus hole wiring.

vnode

Virtual node data structure and tree-building helpers.

Classes:

Name Description
FieldState

Signals representing a field's value, error message, and touched state.

ReactiveProps

Reactive proxy over a component's props dict.

Resource

Async data accessor with reactive loading/error state.

Signal

Mutable reactive container that notifies observers on change.

VNode

Virtual node representing an element, text, component, or reactive hole.

Element

Thin wrapper around a DOM node with convenience methods.

Ref

Mutable container holding a reference to an Element.

DomEvent

The event object Wybthon passes to delegated handlers.

Route

Declarative route definition mapping a path to a component.

Context

Opaque context identifier paired with a default value.

Functions:

Name Description
is_dev_mode

Return whether development mode is currently active.

set_dev_mode

Enable or disable development mode warnings globally.

forward_ref

Create a component that forwards a ref prop to a child element.

a11y_control_attrs

Return ARIA attributes for an input or select control bound to a field.

bind_checkbox

Bind a checkbox input to a boolean field.

bind_select

Bind a <select> element to a field, updating value on change.

bind_text

Bind a text input to a field with validation on every input event.

email

Validate a basic email address format with a lightweight regex.

error_message_attrs

Return attributes for an accessible error-message container.

form_state

Create a form state map from a dict of initial values.

max_length

Validate that the stringified value length is at most n.

min_length

Validate that the stringified value length is at least n.

on_submit

Create a submit handler that prevents default and forwards to handler.

on_submit_validated

Submit handler that validates the whole form before calling handler.

required

Validate that a value is present and non-empty.

rules_from_schema

Build a validators map from a small declarative schema.

validate

Return the first validation error, or None when all validators pass.

validate_field

Validate a single field and update its error and touched signals.

validate_form

Validate every field in a form against a rules map.

batch

Batch signal updates so dependent effects flush once at the end.

catch_error

Run fn with an error handler, catching errors thrown now or later.

children

Resolve and memoize reactive children, returning a memo getter.

create_computed

Create an eagerly-run computation in the pure (pre-render) phase.

create_deferred

Return a getter that trails source, updating on the next event-loop tick.

create_effect

Create an auto-tracking reactive effect.

create_memo

Create an auto-tracking computed value and return its getter.

create_reaction

Create an on-change reaction with manual tracking.

create_render_effect

Create an effect that runs in the render phase, before user effects.

create_resource

Create an async Resource accessor.

create_root

Run fn inside an independent reactive root.

create_selector

Create an O(1) selection signal.

create_signal

Create a reactive signal and return (getter, setter).

create_unique_id

Return a process-unique id string (e.g., for for/id attribute pairs).

get_owner

Return the current reactive owner scope, if any.

get_props

Return the ReactiveProps proxy for the current component.

index_array

Map a reactive list with stable per-index scopes.

map_array

Map a reactive list with stable per-item scopes (keyed by identity).

merge_props

Merge multiple prop sources into a reactive proxy.

on

Create an effect with explicit dependencies.

on_cleanup

Register a cleanup callback on the active reactive owner.

on_error

Register an error handler on the current reactive owner scope.

on_mount

Register a callback to run once after the component mounts.

run_with_owner

Run fn under the given ownership scope.

split_props

Split a props source into groups by key name, plus a rest group.

untrack

Run fn without tracking any signal reads.

create_mutable

Create a directly-writable reactive store proxy.

create_store

Create a reactive store from an initial value.

modify_mutable

Apply a batched modification to a create_mutable proxy.

produce

Create a producer for batch-mutating store state.

reconcile

Diff external data into a store, keeping identity for unchanged items.

unwrap

Return the raw data behind a store proxy (non-reactive).

Fragment

Group multiple children without adding an extra DOM wrapper element.

dynamic

Create a reactive-hole VNode that re-evaluates getter on dependency changes.

h

Create a VNode from a tag, props, and children.

is_getter

Return True when value is a zero-arg callable suitable for a reactive hole.

ErrorBoundary

Catch render errors in children and display a fallback.

Portal

Render children into a different DOM container.

render

Render a VNode tree into a container element.

Link

Anchor element component that navigates via the History API.

Router

Function component that renders the matched route's component.

navigate

Programmatically change the current path and update current_path.

Suspense

Show a fallback while resources read under the boundary are pending.

SuspenseList

Coordinate the reveal order of multiple Suspense boundaries.

Provider

Context provider component.

create_context

Create a new Context with the given default value.

use_context

Read the current value for ctx from the ownership tree.

Dynamic

Render a dynamically-chosen component.

For

Render a list of items using a per-item mapping function.

Index

Render a list by index with a stable item getter.

Match

Declare a branch inside a Switch.

Show

Conditionally render children when when is truthy.

Switch

Render the first matching Match branch, or fallback.

Attributes:

Name Type Description
DEV_MODE bool

Process-wide flag toggling Wybthon's development warnings.

current_path Signal[str]

Signal containing the current pathname plus query string.

DEV_MODE module-attribute

DEV_MODE: bool = True

Process-wide flag toggling Wybthon's development warnings.

Defaults to True. Production builds should call set_dev_mode(False) at startup.

current_path module-attribute

current_path: Signal[str] = Signal(_current_url())

Signal containing the current pathname plus query string.

Updated by navigate and by the global popstate listener (back/forward navigation). Read it inside reactive scopes to re-render when the URL changes.

FieldState dataclass

FieldState(value: Signal[Any], error: Signal[Optional[str]], touched: Signal[bool])

Signals representing a field's value, error message, and touched state.

Attributes:

Name Type Description
value Signal[Any]

Signal holding the current input value.

error Signal[Optional[str]]

Signal holding the latest validation error message, or None when valid.

touched Signal[bool]

Signal that becomes True once the user has interacted with the field. Useful for delaying error display until the user has had a chance to respond.

ReactiveProps

ReactiveProps(props: dict, defaults: Optional[Dict[str, Any]] = None)

Reactive proxy over a component's props dict.

Every attribute or item access returns a reactive accessor: a zero-arg callable that returns the current value and tracks the read. This mirrors SolidJS's props.x semantics, adapted to Python.

Access patterns:

Expression Returns Notes
props.name callable getter Stable across reads.
props.name() current value Tracked when called inside an effect or hole.
props["name"] callable getter Same as props.name.
props.get("name", default) callable getter Returns default when missing.
props.value("name", default) current value One-shot snapshot, with auto-unwrap.

Embed the accessor directly in the VNode tree to create an automatic reactive hole; the surrounding DOM region updates only when the prop changes.

Example
@component
def Greeting():
    props = get_props()
    # Auto-hole: only the text node updates when ``name`` changes.
    return p("Hello, ", props.name, "!")
Note

ReactiveProps is read-only. Parents and the reconciler update it via the internal _update method.

Methods:

Name Description
value

Return the current value for key (tracked, with auto-unwrap).

get

Return a callable getter for key, falling back to default if missing.

keys

Return the prop names currently set on this instance.

values

Return current prop values as a list (tracked).

items

Return (key, current_value) pairs (tracked).

value

value(key: str, default: Any = _MISSING) -> Any

Return the current value for key (tracked, with auto-unwrap).

If the stored prop value is a getter, it's invoked and the result returned, mirroring _make_getter. If default is provided, it's returned when key is absent from both the props dict and the component's parameter defaults.

Parameters:

Name Type Description Default
key str

Prop name.

required
default Any

Value returned when the key is missing. When omitted, missing keys yield None.

_MISSING

Returns:

Type Description
Any

The current prop value (auto-unwrapped if it's a getter).

get

get(key: str, default: Any = None) -> Callable[[], Any]

Return a callable getter for key, falling back to default if missing.

When key exists on the prop bag (in raw props, prior signals, or component-parameter defaults), the returned getter reads the underlying signal: a tracking scope subscribes to it.

When key is missing, the getter returns default on each call without creating a tracked signal. This means repeated get(key, x) / get(key, y) calls each return their own default (no sticky behavior). Components that need reactivity for a possibly-missing prop should declare it as a parameter with a default value; @component ensures a signal is created up front so future updates always propagate.

Parameters:

Name Type Description Default
key str

Prop name.

required
default Any

Value returned by the fallback getter when key is missing.

None

Returns:

Type Description
Callable[[], Any]

A zero-arg callable. Subscribers to a missing-key getter are

Callable[[], Any]

not notified when the prop later appears.

keys

keys() -> Any

Return the prop names currently set on this instance.

The result reflects the latest props pushed into the proxy (it's not tracked as a reactive read).

values

values() -> Any

Return current prop values as a list (tracked).

items

items() -> Any

Return (key, current_value) pairs (tracked).

Resource

Resource(fetcher: FetchFn, source: Optional[Callable[[], Any]] = None, *, initial_value: Any = _MISSING)

Bases: Generic[R]

Async data accessor with reactive loading/error state.

Matches SolidJS's resource shape: the resource is the accessor. Call it to read the current data (tracked); read loading, error, latest, and state as properties (also tracked).

While a resource is in its initial "pending" state, reading it under a Suspense boundary automatically registers it with that boundary; no manual wiring is needed. Refetches ("refreshing" state) don't re-trigger Suspense; the previous data stays available, matching SolidJS.

States:

  • "unresolved": never fetched (source was None/False).
  • "pending": first fetch in flight, no data yet.
  • "ready": data available.
  • "refreshing": refetch in flight, previous data still readable.
  • "errored": last fetch raised.
Example
async def load_user(user_id, signal=None):
    resp = await fetch(f"/api/users/{user_id}")
    return await resp.json()

user = create_resource(user_id, load_user)
p("Name: ", span(lambda: (user() or {}).get("name", "...")))

Methods:

Name Description
mutate

Set the resource's data directly, without fetching.

refetch

Cancel any in-flight request and start a new fetch.

cancel

Abort the current in-flight fetch, if any.

Attributes:

Name Type Description
loading bool

True while a fetch is in flight (tracked read).

error Optional[Any]

The most recent exception, or None (tracked read).

latest Optional[R]

The most recent data, even while refreshing (tracked read).

state str

The current lifecycle state string (tracked read).

loading property

loading: bool

True while a fetch is in flight (tracked read).

error property

error: Optional[Any]

The most recent exception, or None (tracked read).

latest property

latest: Optional[R]

The most recent data, even while refreshing (tracked read).

Unlike calling the resource, reading latest never registers with a Suspense boundary.

state property

state: str

The current lifecycle state string (tracked read).

mutate

mutate(value: Union[R, Callable[[Optional[R]], R]]) -> Optional[R]

Set the resource's data directly, without fetching.

Supports functional updates like a signal setter. Clears any error and marks the resource "ready".

Parameters:

Name Type Description Default
value Union[R, Callable[[Optional[R]], R]]

The new data, or a callable receiving the current data.

required

Returns:

Type Description
Optional[R]

The stored value.

refetch

refetch() -> None

Cancel any in-flight request and start a new fetch.

The resource enters "pending" (first fetch) or "refreshing" (data already present). Older in-flight tasks are ignored when they resolve.

cancel

cancel() -> None

Abort the current in-flight fetch, if any.

Calls AbortController.abort() on the wrapped browser controller, cancels the asyncio task, and resets loading to False without touching the data or error state.

Signal

Signal(value: T, *, equals: Any = _DEFAULT_EQUALS)

Bases: Generic[T]

Mutable reactive container that notifies observers on change.

Most code uses create_signal which returns a (getter, setter) tuple instead of exposing Signal instances directly. This class is part of the public surface so Signal[T] can be used in type hints.

Parameters:

Name Type Description Default
value T

The initial value.

required
equals Any

Equality policy. See create_signal for the full semantics.

_DEFAULT_EQUALS

Methods:

Name Description
get

Return the current value and subscribe the active computation.

peek

Return the current value without subscribing the active computation.

set

Write a new value and synchronously notify observers if it changed.

get

get() -> T

Return the current value and subscribe the active computation.

When called inside an effect, memo, or reactive hole, this signal is added to that computation's dependency set so it re-runs on future writes. Outside a tracking context the read is untracked.

Returns:

Type Description
T

The current value held by the signal.

peek

peek() -> T

Return the current value without subscribing the active computation.

set

set(value: T) -> None

Write a new value and synchronously notify observers if it changed.

Equality is determined by the equals policy passed to the constructor (default: is then ==, with equals=False to bypass the check entirely). Outside a batch, dependent memos become readable immediately and effects run before this call returns.

Parameters:

Name Type Description Default
value T

The new value to store.

required

VNode

VNode(tag: Optional[Union[str, Callable[..., Any]]], props: Optional[PropsDict] = None, children: Optional[List[ChildType]] = None, key: Optional[Union[str, int]] = None)

Virtual node representing an element, text, component, or reactive hole.

Uses __slots__ for a compact memory layout and faster attribute access, which is meaningful when authoring large lists. Internal attributes (el, subtree, render_effect, component_ctx, _frag_end) are populated by the reconciler when the VNode is mounted.

Attributes:

Name Type Description
tag

Element tag name ("div"), special tag ("_text", "_dynamic", "_fragment"), or component callable.

props

Mapping of prop names to values. Event handlers, attributes, and reactive accessors all live here.

children List[Any]

List of child VNode instances (or strings, before normalization).

key

Optional stable identity used for keyed list reconciliation.

el Optional[int]

Kernel node id of this VNode's DOM node once mounted (for fragments, the start marker; for holes, the end marker).

owner_scope Optional[Any]

Optional reactive Owner under which this VNode should be mounted. Set by For/Index so effects created while mounting a cached row belong to the row's scope rather than to the list's re-running effect.

Element

Element(tag: Optional[str] = None, existing: bool = False, node: Any = None, node_id: Optional[int] = None)

Thin wrapper around a DOM node with convenience methods.

Element can be constructed in four ways:

  • With a tag name to create a brand-new node (Element("div")).
  • With a CSS selector and existing=True to wrap an existing node (Element("#root", existing=True)).
  • With an opaque node value to wrap a node returned by another API.
  • With a kernel node_id (used internally by the renderer for refs and event targets); the raw node is materialized lazily on first access.

The wrapper proxies common form-input properties (value, checked, files) so handlers can read state from e.target.value exactly as in React or SolidJS.

Create a new element, wrap an existing one, or wrap a node handle.

Parameters:

Name Type Description Default
tag Optional[str]

Tag name ("div") or, when existing=True, a CSS selector identifying the node to wrap.

None
existing bool

If True, query the document for tag instead of creating a new element.

False
node Any

Raw underlying DOM node to wrap. When provided, tag and existing are ignored.

None
node_id Optional[int]

Kernel node id to wrap. The raw node is fetched on first element access.

None

Raises:

Type Description
ValueError

If neither node, node_id, nor a usable tag is provided.

Methods:

Name Description
set_text

Replace the text content of this element.

append_to

Append this element to parent.

append

Append an Element or a text string as a child node.

remove

Detach this element from its parent (no-op if already detached).

load_html

Fetch HTML from url and assign it to innerHTML.

set_html

Replace this element's content with the provided HTML string.

set_attr

Set an attribute on this element, with text-node fallbacks.

get_attr

Return the attribute value for name, or None when absent.

remove_attr

Remove an attribute from this element.

set_style

Set CSS properties using a dict and/or keyword arguments.

add_class

Add one or more CSS classes to this element.

remove_class

Remove one or more CSS classes from this element.

toggle_class

Toggle a CSS class, optionally forcing on/off.

has_class

Return True if the element currently has the given class.

query

Query a single element by CSS selector.

query_all

Query all matching elements by CSS selector.

find

Return the first matching descendant Element, or None.

find_all

Return all matching descendant elements as a list.

attach_ref

Store this element on ref.current.

Attributes:

Name Type Description
element Any

The raw underlying DOM node, materialized on first access.

node_id int

This element's kernel node id, registering the raw node if needed.

value Any

Current value of an <input>, <textarea>, or <select>.

checked bool

Checked state of a checkbox or radio input.

files Any

FileList for file inputs (<input type="file">), or None.

element property

element: Any

The raw underlying DOM node, materialized on first access.

For id-backed elements this commits pending batched DOM ops first, so the node exists and reflects every queued mutation.

node_id property

node_id: int

This element's kernel node id, registering the raw node if needed.

value property writable

value: Any

Current value of an <input>, <textarea>, or <select>.

checked property writable

checked: bool

Checked state of a checkbox or radio input.

files property

files: Any

FileList for file inputs (<input type="file">), or None.

set_text

set_text(text: str) -> None

Replace the text content of this element.

append_to

append_to(parent: Element) -> None

Append this element to parent.

append

append(child: Union[Element, str]) -> None

Append an Element or a text string as a child node.

remove

remove() -> None

Detach this element from its parent (no-op if already detached).

load_html async

load_html(url: str) -> None

Fetch HTML from url and assign it to innerHTML.

Parameters:

Name Type Description Default
url str

URL to fetch via the browser's fetch API.

required

set_html

set_html(html: str) -> None

Replace this element's content with the provided HTML string.

Caution

This bypasses the renderer's diffing and does not sanitize input. Avoid passing untrusted HTML.

set_attr

set_attr(name: str, value: Union[str, int, float, bool]) -> None

Set an attribute on this element, with text-node fallbacks.

Parameters:

Name Type Description Default
name str

Attribute name (or nodeValue/text for text nodes).

required
value Union[str, int, float, bool]

Attribute value; coerced to str.

required

get_attr

get_attr(name: str) -> Optional[str]

Return the attribute value for name, or None when absent.

remove_attr

remove_attr(name: str) -> None

Remove an attribute from this element.

set_style

set_style(styles: Optional[Dict[str, Union[str, int]]] = None, **style_kwargs: Union[str, int]) -> None

Set CSS properties using a dict and/or keyword arguments.

Parameters:

Name Type Description Default
styles Optional[Dict[str, Union[str, int]]]

Optional mapping of CSS property name to value.

None
**style_kwargs Union[str, int]

Additional CSS properties (last write wins if a key appears in both).

{}

add_class

add_class(*class_names: str) -> None

Add one or more CSS classes to this element.

remove_class

remove_class(*class_names: str) -> None

Remove one or more CSS classes from this element.

toggle_class

toggle_class(class_name: str, force: Optional[bool] = None) -> None

Toggle a CSS class, optionally forcing on/off.

Parameters:

Name Type Description Default
class_name str

Class to toggle.

required
force Optional[bool]

Pass True to ensure the class is added, False to ensure it's removed; None toggles based on the current state.

None

has_class

has_class(class_name: str) -> bool

Return True if the element currently has the given class.

query classmethod

query(selector: str, within: Optional[Element] = None) -> Optional[Element]

Query a single element by CSS selector.

Commits pending batched DOM ops first so nodes created earlier in the same update are visible to the query.

Parameters:

Name Type Description Default
selector str

CSS selector string.

required
within Optional[Element]

Optional parent Element to scope the query to. Defaults to document.

None

Returns:

Type Description
Optional[Element]

The first matching Element, or None if no node matches.

query_all classmethod

query_all(selector: str, within: Optional[Element] = None) -> List[Element]

Query all matching elements by CSS selector.

Parameters:

Name Type Description Default
selector str

CSS selector string.

required
within Optional[Element]

Optional parent Element to scope the query to. Defaults to document.

None

Returns:

Type Description
List[Element]

A list of wrapped Element instances (possibly empty).

find

find(selector: str) -> Optional[Element]

Return the first matching descendant Element, or None.

find_all

find_all(selector: str) -> List[Element]

Return all matching descendant elements as a list.

attach_ref

attach_ref(ref: Ref) -> None

Store this element on ref.current.

Ref

Ref()

Mutable container holding a reference to an Element.

Instantiate with Ref() and pass to elements via the ref= prop. After mount, ref.current points at the wrapped element; after unmount, it is reset to None.

Example
from wybthon import Ref, on_mount
from wybthon.html import input_

input_ref = Ref()

def focus_on_mount():
    on_mount(lambda: input_ref.current and input_ref.current.element.focus())

input_(type="text", ref=input_ref)

Initialize an empty ref pointing at None.

DomEvent

DomEvent(payload: Dict[str, Any], current_target: Optional[Any] = None)

The event object Wybthon passes to delegated handlers.

Built from the kernel's dispatch payload rather than a JsProxy, so reading it is free of bridge crossings. Use raw to reach the native event object for anything not covered by the payload.

Attributes:

Name Type Description
type

Event type string (e.g., "click").

target

Payload-backed view of the original event target, exposing value, checked, files, and element.

current_target

The element whose handler is currently running (an id-backed Element).

key

KeyboardEvent.key, or None for non-keyboard events.

code

KeyboardEvent.code, or None.

alt_key

Whether Alt was held.

ctrl_key

Whether Ctrl was held.

meta_key

Whether Meta/Cmd was held.

shift_key

Whether Shift was held.

button

MouseEvent.button (0 for primary).

client_x

Pointer x position, when applicable.

client_y

Pointer y position, when applicable.

Build an event from a dispatch payload dict.

Parameters:

Name Type Description Default
payload Dict[str, Any]

Parsed dispatch payload from the kernel.

required
current_target Optional[Any]

The Element whose handler is being invoked.

None

Methods:

Name Description
prevent_default

Prevent the default browser action for this event.

stop_propagation

Stop the delegated dispatch from walking further up the tree.

raw property

raw: Any

The native browser event object (escape hatch).

Only valid synchronously during dispatch; returns None afterwards.

prevent_default

prevent_default() -> None

Prevent the default browser action for this event.

stop_propagation

stop_propagation() -> None

Stop the delegated dispatch from walking further up the tree.

Also stops native propagation so other JS listeners above don't fire.

Route dataclass

Route(path: str, component: Union[Callable[[Dict[str, Any]], VNode], type], children: Optional[List['Route']] = None)

Declarative route definition mapping a path to a component.

Attributes:

Name Type Description
path str

Route pattern (e.g., "/users/:id", "/docs/*").

component Union[Callable[[Dict[str, Any]], VNode], type]

A function component or class to render when the path matches.

children Optional[List['Route']]

Optional nested routes whose paths are joined with this route's path.

Context dataclass

Context(id: int, default: Any)

Opaque context identifier paired with a default value.

Returned by create_context. Treat the object as opaque: pass it to a Provider and to use_context but don't rely on its fields.

Attributes:

Name Type Description
id int

Process-unique integer used as the storage key on owner scopes.

default Any

Value returned by use_context when no enclosing provider is found.

Methods:

Name Description
Provider

Build a provider VNode for this context (SolidJS-style shorthand).

Provider

Provider(value: Any = None, children: Any = None) -> Any

Build a provider VNode for this context (SolidJS-style shorthand).

Equivalent to h(Provider, {"context": self, "value": value, "children": children}).

Parameters:

Name Type Description Default
value Any

The value to expose to descendants.

None
children Any

A VNode or list of VNodes rendered transparently.

None

Returns:

Type Description
Any

A provider component VNode.

Example
Theme = create_context("light")
Theme.Provider(value="dark", children=[App()])

is_dev_mode

is_dev_mode() -> bool

Return whether development mode is currently active.

set_dev_mode

set_dev_mode(enabled: bool) -> None

Enable or disable development mode warnings globally.

Parameters:

Name Type Description Default
enabled bool

When False, warn and warn_once become no-ops and tracebacks are suppressed in log_error.

required

forward_ref

forward_ref(render_fn: Callable[..., Any]) -> Callable[..., Any]

Create a component that forwards a ref prop to a child element.

The wrapped function receives (props, ref) instead of (props,), where ref is the value of the ref prop (or None). ref is stripped from props (matching React's forwardRef semantics), so the wrapped function only sees its own concerns.

Parameters:

Name Type Description Default
render_fn Callable[..., Any]

A callable taking (props, ref) and returning a VNode subtree.

required

Returns:

Type Description
Callable[..., Any]

A component callable that forwards the ref prop to render_fn.

Example
FancyInput = forward_ref(lambda props, ref: input_(
    type="text", ref=ref, class_="fancy",
))

my_ref = Ref()
h(FancyInput, {"ref": my_ref})

a11y_control_attrs

a11y_control_attrs(field: FieldState, *, described_by_id: Optional[str] = None) -> Dict[str, Any]

Return ARIA attributes for an input or select control bound to a field.

  • aria-invalid is set to "true" when the field currently has an error, otherwise "false".
  • aria-describedby references described_by_id when an error is present, allowing screen readers to announce the message.

Parameters:

Name Type Description Default
field FieldState

Bound FieldState.

required
described_by_id Optional[str]

Optional id of the element rendered by error_message_attrs.

None

Returns:

Type Description
Dict[str, Any]

Props dict to spread onto the control.

bind_checkbox

bind_checkbox(field: FieldState) -> Dict[str, Any]

Bind a checkbox input to a boolean field.

Parameters:

Name Type Description Default
field FieldState

Target FieldState (treated as holding a bool).

required

Returns:

Type Description
Dict[str, Any]

Props dict suitable for spreading onto a checkbox

Dict[str, Any]

(checked + on_change).

bind_select

bind_select(field: FieldState) -> Dict[str, Any]

Bind a <select> element to a field, updating value on change.

Parameters:

Name Type Description Default
field FieldState

Target FieldState.

required

Returns:

Type Description
Dict[str, Any]

Props dict suitable for spreading onto a <select> element

Dict[str, Any]

(value + on_change).

bind_text

bind_text(field: FieldState, *, validators: Optional[List[Validator]] = None) -> Dict[str, Any]

Bind a text input to a field with validation on every input event.

Parameters:

Name Type Description Default
field FieldState

Target FieldState.

required
validators Optional[List[Validator]]

Optional list of validators. When provided, the field's error signal is updated on every keystroke.

None

Returns:

Type Description
Dict[str, Any]

Props dict suitable for spreading onto a text input

Dict[str, Any]

(value + on_input).

email

email(message: str = 'Invalid email address') -> Validator

Validate a basic email address format with a lightweight regex.

The validator accepts None and empty strings as valid so it can be combined with required (which handles the "missing" case explicitly).

Parameters:

Name Type Description Default
message str

Error message used when the value doesn't match.

'Invalid email address'

Returns:

Type Description
Validator

A validator returning message on bad input, otherwise

Validator

None.

error_message_attrs

error_message_attrs(*, id: str) -> Dict[str, Any]

Return attributes for an accessible error-message container.

The container becomes a polite live region so that updates are announced to assistive technology without interrupting the user.

Parameters:

Name Type Description Default
id str

DOM id to assign to the error container. Pair with a11y_control_attrs so the input references this element via aria-describedby.

required

Returns:

Type Description
Dict[str, Any]

Props dict to spread onto the error container element.

form_state

form_state(initial: Dict[str, Any]) -> Dict[str, FieldState]

Create a form state map from a dict of initial values.

Parameters:

Name Type Description Default
initial Dict[str, Any]

Mapping of field name to initial value.

required

Returns:

Type Description
Dict[str, FieldState]

A dict mapping each field name to a freshly-created

Dict[str, FieldState]

max_length

max_length(n: int, message: Optional[str] = None) -> Validator

Validate that the stringified value length is at most n.

Parameters:

Name Type Description Default
n int

Maximum allowed length.

required
message Optional[str]

Optional override for the default error message.

None

Returns:

Type Description
Validator

A validator that returns the message when `len(str(value)) >

Validator

nor whenvalueisNone, otherwiseNone`.

min_length

min_length(n: int, message: Optional[str] = None) -> Validator

Validate that the stringified value length is at least n.

Parameters:

Name Type Description Default
n int

Minimum allowed length.

required
message Optional[str]

Optional override for the default error message.

None

Returns:

Type Description
Validator

A validator that returns the message when `len(str(value)) <

Validator

nor whenvalueisNone, otherwiseNone`.

on_submit

on_submit(handler: Callable[[Dict[str, FieldState]], Any], form: Dict[str, FieldState]) -> Callable[[Any], Any]

Create a submit handler that prevents default and forwards to handler.

Parameters:

Name Type Description Default
handler Callable[[Dict[str, FieldState]], Any]

Callback invoked with the form state when submit fires.

required
form Dict[str, FieldState]

Form state map produced by form_state.

required

Returns:

Type Description
Callable[[Any], Any]

An event handler suitable for on_submit= on a <form>.

on_submit_validated

on_submit_validated(rules: Dict[str, List[Validator]], handler: Callable[[Dict[str, FieldState]], Any], form: Dict[str, FieldState]) -> Callable[[Any], Any]

Submit handler that validates the whole form before calling handler.

Prevents the default submit action, validates via validate_form, and invokes handler only when validation passes.

Parameters:

Name Type Description Default
rules Dict[str, List[Validator]]

Mapping from field name to a list of validators.

required
handler Callable[[Dict[str, FieldState]], Any]

Callback invoked with the form state on success.

required
form Dict[str, FieldState]

Form state map produced by form_state.

required

Returns:

Type Description
Callable[[Any], Any]

An event handler suitable for on_submit= on a <form>.

required

required(message: str = 'This field is required') -> Validator

Validate that a value is present and non-empty.

Parameters:

Name Type Description Default
message str

Error message used when the value is missing or blank.

'This field is required'

Returns:

Type Description
Validator

A validator that returns message for None or empty strings

Validator

(after strip()), otherwise None.

rules_from_schema

rules_from_schema(schema: Dict[str, Dict[str, Any]]) -> Dict[str, List[Validator]]

Build a validators map from a small declarative schema.

Supported per-field keys:

  • required: bool or str (if a string, it's used as the custom message).
  • min_length: int. Optional custom message via min_length_message.
  • max_length: int. Optional custom message via max_length_message.
  • email: bool or str (if a string, it's used as the custom message).

Parameters:

Name Type Description Default
schema Dict[str, Dict[str, Any]]

Mapping from field name to its rule spec dict.

required

Returns:

Type Description
Dict[str, List[Validator]]

A validators map suitable for

Dict[str, List[Validator]]
Example
rules_from_schema({
    "name": {"required": True, "min_length": 2},
    "email": {"email": True},
})

validate

validate(value: Any, validators: List[Validator]) -> Optional[str]

Return the first validation error, or None when all validators pass.

Parameters:

Name Type Description Default
value Any

Value to validate.

required
validators List[Validator]

Ordered list of validators applied with short-circuit semantics.

required

Returns:

Type Description
Optional[str]

The error message from the first failing validator, or None

Optional[str]

if every validator returns None.

validate_field

validate_field(field: FieldState, validators: Optional[List[Validator]] = None) -> Optional[str]

Validate a single field and update its error and touched signals.

Parameters:

Name Type Description Default
field FieldState

Target FieldState.

required
validators Optional[List[Validator]]

Validators to apply. When omitted or empty, the field is treated as valid.

None

Returns:

Type Description
Optional[str]

The first error message produced by the validators, or None

Optional[str]

when the field is valid.

validate_form

validate_form(form: Dict[str, FieldState], rules: Dict[str, List[Validator]]) -> Tuple[bool, Dict[str, Optional[str]]]

Validate every field in a form against a rules map.

Mutates each field's touched and error signals as a side effect.

Parameters:

Name Type Description Default
form Dict[str, FieldState]

Form state map (typically produced by form_state).

required
rules Dict[str, List[Validator]]

Mapping from field name to a list of validators. Unknown field names are ignored.

required

Returns:

Type Description
bool

A (is_valid, errors) tuple where is_valid is True only

Dict[str, Optional[str]]

when every validator passes and errors maps each field name

Tuple[bool, Dict[str, Optional[str]]]

to its current error message (or None).

batch

batch(fn: Optional[Callable[[], T]] = None) -> Union[T, _Batch]

Batch signal updates so dependent effects flush once at the end.

Two call shapes are supported:

  1. Context manager (Pythonic):
    with batch():
        set_a(1)
        set_b(2)
    
  2. Callback (SolidJS style):
    batch(lambda: (set_a(1), set_b(2)))
    

When called with a function, the function's return value is returned. Effects are flushed synchronously when the outermost batch exits, matching SolidJS semantics.

Parameters:

Name Type Description Default
fn Optional[Callable[[], T]]

Optional zero-arg callable. When omitted, returns a context manager.

None

Returns:

Type Description
Union[T, _Batch]

Either a _Batch context manager (when fn is None) or the

Union[T, _Batch]

return value of fn.

catch_error

catch_error(fn: Callable[[], T], handler: Callable[[Any], Any]) -> Optional[T]

Run fn with an error handler, catching errors thrown now or later.

Matches SolidJS's catchError. The handler receives exceptions raised synchronously by fn and exceptions raised later by any effect created inside fn (they route up the ownership tree to the nearest handler).

Parameters:

Name Type Description Default
fn Callable[[], T]

Zero-arg callable to execute under the error scope.

required
handler Callable[[Any], Any]

Callback receiving the exception.

required

Returns:

Type Description
Optional[T]

The return value of fn, or None when fn raised.

Example
result = catch_error(lambda: risky_setup(), lambda e: report(e))

children

children(fn: Callable[[], Any]) -> Callable[[], List[Any]]

Resolve and memoize reactive children, returning a memo getter.

Wraps a getter that returns children (e.g., lambda: props.children()) and returns a memo that flattens nested lists and unwraps callables. Matches SolidJS's children() helper.

Parameters:

Name Type Description Default
fn Callable[[], Any]

Zero-arg getter that returns the raw children value (typically lambda: get_props().children()).

required

Returns:

Type Description
Callable[[], List[Any]]

A zero-arg memo getter producing a flat list of resolved children.

Example
@component
def Card(title=""):
    props = get_props()
    resolved = children(lambda: props.children())
    return section(h3(props.title), *resolved())

create_computed

create_computed(fn: Callable[..., Any]) -> Computation

Create an eagerly-run computation in the pure (pre-render) phase.

Matches SolidJS's createComputed: within one flush, all pending create_computed computations run before any render effects, so signals they write are fully settled before the DOM updates. Prefer create_memo for plain derived values; reach for create_computed only when you must push a value into another signal.

Parameters:

Name Type Description Default
fn Callable[..., Any]

Zero- or one-arg callable.

required

Returns:

Type Description
Computation

The underlying Computation.

create_deferred

create_deferred(source: Callable[[], T]) -> Callable[[], T]

Return a getter that trails source, updating on the next event-loop tick.

A lightweight analogue of SolidJS's createDeferred: reads of the returned getter don't recompute synchronously when source changes; instead, the new value is published asynchronously (via the running asyncio loop when one exists, else immediately). Use it to decouple expensive consumers from rapid-fire updates.

Parameters:

Name Type Description Default
source Callable[[], T]

Zero-arg tracked getter.

required

Returns:

Type Description
Callable[[], T]

A zero-arg getter for the deferred value.

create_effect

create_effect(fn: Callable[..., Any]) -> Computation

Create an auto-tracking reactive effect.

The effect runs immediately and re-runs whenever any signal read inside fn changes. on_cleanup may be called inside fn to register per-run cleanup that runs before re-execution and on disposal.

If fn accepts a positional parameter, the previous return value is passed on each re-execution (None on the first run), matching SolidJS's createEffect(prev => ...).

Inside a component, the effect is automatically disposed on unmount.

Parameters:

Name Type Description Default
fn Callable[..., Any]

Zero- or one-arg callable. When it accepts an argument, the previous return value is forwarded.

required

Returns:

Type Description
Computation

The underlying Computation. Call .dispose() to stop the effect

Computation

manually.

Example
count, set_count = create_signal(0)
create_effect(lambda prev: (print("was", prev), count())[1])

create_memo

create_memo(fn: Callable[[], T], *, equals: Any = _DEFAULT_EQUALS) -> Callable[[], T]

Create an auto-tracking computed value and return its getter.

Re-computes lazily, only when read after a tracked source changed. Inside a component, the underlying computation is disposed on unmount.

Parameters:

Name Type Description Default
fn Callable[[], T]

Zero-arg callable producing the derived value.

required
equals Any

Equality policy controlling when the memo's own observers are notified after a recompute. Same semantics as create_signal: the default is value equality with an identity fast path, False always notifies, and a callable (old, new) -> bool skips notification when it returns True.

_DEFAULT_EQUALS

Returns:

Type Description
Callable[[], T]

A zero-arg callable. Reading it inside a tracking scope creates

Callable[[], T]

a dependency on the memoised value. Its .peek() method returns

Callable[[], T]

the (up-to-date) value without subscribing the caller.

Example
doubled = create_memo(lambda: count() * 2)
print(doubled())      # reactive read
print(doubled.peek())  # untracked read

# Notify only when the result list changes length:
heads = create_memo(lambda: items()[:5], equals=lambda a, b: len(a) == len(b))

create_reaction

create_reaction(on_invalidate: Callable[[], Any]) -> Callable[[Callable[[], Any]], None]

Create an on-change reaction with manual tracking.

Matches SolidJS's createReaction: the returned track function runs its argument once with tracking enabled; the first time any tracked dependency changes, on_invalidate fires (untracked) and tracking stops until track is called again. Useful for "notify me once" patterns where the rendering of the change is decoupled from its detection.

Parameters:

Name Type Description Default
on_invalidate Callable[[], Any]

Zero-arg callback invoked once per tracked change.

required

Returns:

Type Description
Callable[[Callable[[], Any]], None]

A track(fn) function. Call it with a zero-arg callable whose

Callable[[Callable[[], Any]], None]

signal reads should be tracked.

Example
count, set_count = create_signal(0)
track = create_reaction(lambda: print("count changed!"))

track(count)     # start tracking
set_count(1)     # prints "count changed!"
set_count(2)     # nothing: tracking stopped
track(count)     # re-arm

create_render_effect

create_render_effect(fn: Callable[..., Any]) -> Computation

Create an effect that runs in the render phase, before user effects.

Matches SolidJS's createRenderEffect: within one flush, all pending render effects execute before any create_effect callbacks, and before the batched DOM ops are committed. Wybthon's internal reactive holes and prop bindings run in this phase, so a render effect observes the DOM in the same state the framework's own bindings do (updates emitted but not yet committed).

Parameters:

Name Type Description Default
fn Callable[..., Any]

Zero- or one-arg callable (the previous return value is forwarded when accepted, as with create_effect).

required

Returns:

Type Description
Computation

The underlying Computation.

create_resource

create_resource(source_or_fetcher: Union[Callable[[], Any], Callable[..., Awaitable[R]]], fetcher: Optional[Callable[..., Awaitable[R]]] = None, *, initial_value: Any = _MISSING) -> Resource[R]

Create an async Resource accessor.

Can be called two ways:

  • create_resource(fetcher): simple fetcher, fetches immediately.
  • create_resource(source, fetcher): fetches whenever the source getter's tracked value changes; when the source yields None or False the fetch is skipped (the resource stays unresolved).

The fetcher may be sync or async. When it declares a positional parameter, the current source value is passed as the first argument. When it accepts a signal keyword argument, an AbortSignal is passed for cancellation support in the browser.

Parameters:

Name Type Description Default
source_or_fetcher Union[Callable[[], Any], Callable[..., Awaitable[R]]]

When called with one argument, this is the fetcher. When called with two, this is the source getter (typically a signal accessor).

required
fetcher Optional[Callable[..., Awaitable[R]]]

Optional fetcher. Required when source_or_fetcher is a source getter.

None
initial_value Any

Optional seed data. When provided, the resource starts "ready" with this value, so reading it never triggers a Suspense fallback; the first fetch runs as a "refreshing" state instead of "pending", matching SolidJS's initialValue option.

_MISSING

Returns:

Type Description
Resource[R]

A Resource[R]. Call it to read the data; read .loading,

Resource[R]

.error, .latest, and .state for the surrounding UI state.

Example
user_id, set_user_id = create_signal(1)

async def load_user(uid, signal=None):
    resp = await fetch(f"/api/users/{uid}")
    return await resp.json()

user = create_resource(user_id, load_user)
cached = create_resource(load_all, initial_value=[])

create_root

create_root(fn: Callable[[Callable[[], None]], T]) -> T

Run fn inside an independent reactive root.

Useful for spawning long-lived reactive work that shouldn't be tied to the surrounding component's lifecycle (e.g., global stores).

Parameters:

Name Type Description Default
fn Callable[[Callable[[], None]], T]

Callable receiving a dispose callback. Calling dispose() tears down the root and any effects created inside it.

required

Returns:

Type Description
T

Whatever fn returns.

Example
result = create_root(lambda dispose: setup_global_state(dispose))

create_selector

create_selector(source: Callable[[], Any]) -> Callable[[Any], bool]

Create an O(1) selection signal.

When source() changes, only computations that previously called the returned is_selected(key) with the old or new key are notified, instead of every subscriber re-running.

Parameters:

Name Type Description Default
source Callable[[], Any]

Zero-arg getter returning the currently-selected key.

required

Returns:

Type Description
Callable[[Any], bool]

A function is_selected(key) -> bool that's reactive to

Callable[[Any], bool]

selection changes.

Example
selected, set_selected = create_signal(1)
is_selected = create_selector(selected)

# Inside a For loop per item:
create_effect(lambda: print("active:", is_selected(item_id)))

create_signal

create_signal(value: T, *, equals: Any = _DEFAULT_EQUALS) -> tuple

Create a reactive signal and return (getter, setter).

Works inside or outside components. Inside a stateful component the signal is captured by the render function's closure and persists naturally; there's no cursor system or "rules of hooks".

The setter supports functional updates, matching SolidJS: when called with a callable, the callable receives the current value and its return value becomes the new value. To store a callable as the signal's value, wrap it: set_fn(lambda _prev: my_callable).

Parameters:

Name Type Description Default
value T

Initial value stored in the signal.

required
equals Any

Equality policy controlling when subscribers are notified. Accepts:

  • The default sentinel (or True): value equality (new == old) with an identity fast-path. Skips notification when the new value is is-identical or ==-equal to the old. This matches Python's natural intuition; re-setting an unchanged value is a no-op, and a fresh container with equal contents also skips notification.
  • False: always notify on every set() call, even when the new value is identical or equal to the old. Useful for "fire a change event" signals.
  • A callable (old, new) -> bool: skip notification when it returns True. Pass equals=lambda a, b: a is b for SolidJS-style identity-only semantics.
_DEFAULT_EQUALS

Returns:

Type Description
tuple

A (getter, setter) tuple. The getter is a zero-arg callable

tuple

suitable for embedding as a reactive hole; its .peek() method

tuple

returns the current value without subscribing the caller. The

tuple

setter returns the value that was stored.

Example
count, set_count = create_signal(0)
print(count())              # 0
set_count(5)
print(count())              # 5
set_count(lambda c: c + 1)  # functional update
print(count())              # 6
count.peek()                # 6, without subscribing

create_unique_id

create_unique_id() -> str

Return a process-unique id string (e.g., for for/id attribute pairs).

Matches SolidJS's createUniqueId.

Returns:

Type Description
str

A short unique string like "wyb-7".

get_owner

get_owner() -> Optional[Owner]

Return the current reactive owner scope, if any.

Capture the owner before crossing async boundaries (e.g., await) and restore it with run_with_owner to maintain proper lifecycle management.

Returns:

Type Description
Optional[Owner]

The active Owner, or None when called outside any reactive

Optional[Owner]

scope.

get_props

get_props() -> 'ReactiveProps'

Return the ReactiveProps proxy for the current component.

The returned object provides reactive access to individual props. Each attribute / index lookup yields a callable getter; call the getter to read the current value (tracked when called inside an effect or hole).

Most components should rely on the destructured parameters provided by @component. Use get_props() for advanced cases such as generic wrappers, key iteration, or proxy-mode interop.

Returns:

Type Description
'ReactiveProps'

The cached ReactiveProps proxy for this component instance.

Raises:

Type Description
RuntimeError

If called outside a component setup phase.

Example
@component
def Greet(name="world"):
    # ``name`` is already a reactive accessor.
    return p("Hello, ", name, "!")

@component
def Advanced():
    props = get_props()
    create_effect(lambda: print("name:", props.name()))

index_array

index_array(source: Callable[[], Optional[List[Any]]], map_fn: Callable[[Callable[[], Any], int], T]) -> Callable[[], List[T]]

Map a reactive list with stable per-index scopes.

Unlike map_array, scopes are keyed by index position. Each slot has a reactive item_getter signal that updates when the value at that index changes.

Parameters:

Name Type Description Default
source Callable[[], Optional[List[Any]]]

Zero-arg getter that returns the current list.

required
map_fn Callable[[Callable[[], Any], int], T]

Called as map_fn(item_getter, index). item_getter() returns the item; index is a plain int (not a getter).

required

Returns:

Type Description
Callable[[], List[T]]

A zero-arg getter producing the mapped list.

Example
items, set_items = create_signal(["A", "B", "C"])
labels = index_array(items, lambda item, idx: f"[{idx}] {item()}")
# labels() == ["[0] A", "[1] B", "[2] C"]

map_array

map_array(source: Callable[[], Optional[List[Any]]], map_fn: Callable[[Callable[[], Any], Callable[[], int]], T]) -> Callable[[], List[T]]

Map a reactive list with stable per-item scopes (keyed by identity).

Items are matched by reference identity. The mapping callback runs once per unique item; when an item leaves the source list, its reactive scope is disposed automatically.

Parameters:

Name Type Description Default
source Callable[[], Optional[List[Any]]]

Zero-arg getter that returns the current list (typically a signal accessor).

required
map_fn Callable[[Callable[[], Any], Callable[[], int]], T]

Called as map_fn(item_getter, index_getter) for each unique item. item_getter() returns the item; index_getter() returns its current position.

required

Returns:

Type Description
Callable[[], List[T]]

A zero-arg getter producing the mapped list. Reading it inside a

Callable[[], List[T]]

reactive scope subscribes to source changes.

Example
items, set_items = create_signal(["A", "B", "C"])
labels = map_array(items, lambda item, idx: f"{idx()}: {item()}")
# labels() == ["0: A", "1: B", "2: C"]

merge_props

merge_props(*sources: Any) -> '_MergedProps'

Merge multiple prop sources into a reactive proxy.

Each source may be a plain dict, a zero-arg getter that returns a dict, or another _MergedProps / _SplitProps. Later sources override earlier ones on key conflicts.

The returned object supports dict-like access ([], .get, in, iteration). When a source is a callable, it's called on each property access, so signal reads inside the getter are tracked by the current reactive computation.

Parameters:

Name Type Description Default
*sources Any

One or more prop sources, in priority order (rightmost wins).

()

Returns:

Type Description
'_MergedProps'

A reactive merged-props proxy.

Example
defaults = {"size": "md", "variant": "solid"}
final = merge_props(defaults, props)
# final["size"] lazily reads from props, then falls back to defaults

on

on(deps: Union[Callable[[], Any], List[Callable[[], Any]]], fn: Callable[..., Any], defer: bool = False) -> Computation

Create an effect with explicit dependencies.

deps may be a single getter or a list of getters. fn receives the current value(s) as positional arguments. Only the listed deps are tracked; the body of fn runs inside untrack.

Parameters:

Name Type Description Default
deps Union[Callable[[], Any], List[Callable[[], Any]]]

One getter or a list of getters to subscribe to.

required
fn Callable[..., Any]

Callback receiving the current dep value(s) on each change.

required
defer bool

When True, skip the first invocation (so fn runs only on subsequent changes, not the initial read).

False

Returns:

Type Description
Computation

The underlying Computation.

Example
on(count, lambda v: print("count is now", v))
on([a, b], lambda va, vb: print(f"a={va}, b={vb}"), defer=True)

on_cleanup

on_cleanup(fn: Callable[[], Any]) -> None

Register a cleanup callback on the active reactive owner.

Lifecycle differs by call site:

  • Inside create_effect: runs before each re-execution and on final disposal.
  • Inside a component's setup phase: runs when the component unmounts.
  • Inside a reactive hole: runs before each hole re-evaluation and when the hole is disposed.

Parameters:

Name Type Description Default
fn Callable[[], Any]

Zero-arg cleanup callback.

required

Raises:

Type Description
RuntimeError

If called outside any reactive scope.

on_error

on_error(handler: Callable[[Any], Any]) -> None

Register an error handler on the current reactive owner scope.

Matches SolidJS's onError: exceptions raised by child computations (effects created under this scope, reactive holes, descendant component setups) route to the nearest ancestor handler. Multiple calls in the same scope chain the handlers; each runs in registration order.

Unlike catch_error, which wraps a single function call in its own scope, on_error protects everything created under the current scope for its remaining lifetime.

Parameters:

Name Type Description Default
handler Callable[[Any], Any]

Callback receiving the exception.

required

Raises:

Type Description
RuntimeError

If called outside any reactive scope.

Example
@component
def Dashboard():
    on_error(lambda exc: report_to_sentry(exc))
    ...

on_mount

on_mount(fn: Callable[[], Any]) -> None

Register a callback to run once after the component mounts.

Must be called during a component's setup phase (the body of a @component function, before the return).

Parameters:

Name Type Description Default
fn Callable[[], Any]

Zero-arg callback invoked once after the first render commits.

required

Raises:

Type Description
RuntimeError

If called outside a component setup phase.

run_with_owner

run_with_owner(owner: Optional[Owner], fn: Callable[[], T]) -> T

Run fn under the given ownership scope.

Useful for restoring context after an await boundary where the reactive owner would otherwise be lost.

Parameters:

Name Type Description Default
owner Optional[Owner]

The owner to install for the duration of fn. Pass None to disable ownership tracking entirely.

required
fn Callable[[], T]

Zero-arg callable to execute.

required

Returns:

Type Description
T

Whatever fn returns.

Example
async def load():
    owner = get_owner()
    data = await fetch_something()
    run_with_owner(owner, lambda: create_effect(lambda: use(data)))

split_props

split_props(props: Any, *key_groups: List[str]) -> Tuple[Any, ...]

Split a props source into groups by key name, plus a rest group.

Parameters:

Name Type Description Default
props Any

A dict, callable getter, or _MergedProps / _SplitProps to split.

required
*key_groups List[str]

One or more lists of keys defining each group.

()

Returns:

Type Description
Any

A tuple (group1, group2, ..., rest) where each group is a

...

reactive proxy that lazily reads from the original props. The

Tuple[Any, ...]

final rest group contains every key not claimed by an earlier

Tuple[Any, ...]

group.

Example
local, rest = split_props(props, ["class", "style"])
# local["class"] lazily reads from props
# rest contains every other key

untrack

untrack(fn: Callable[[], T]) -> T

Run fn without tracking any signal reads.

Useful inside effects when you need to read a signal without creating a dependency, or during component setup to seed local state from a prop without subscribing.

Inside untrack the dev-mode destructured-prop warning is also silenced, so count, set_count = create_signal(untrack(initial)) cleanly opts out of the noise.

Parameters:

Name Type Description Default
fn Callable[[], T]

Zero-arg callable to invoke with tracking suppressed.

required

Returns:

Type Description
T

Whatever fn returns.

Example
create_effect(lambda: print("a changed:", a(), "b is:", untrack(b)))

create_mutable

create_mutable(initial: Any) -> Any

Create a directly-writable reactive store proxy.

Matches SolidJS's createMutable: reads are tracked per path like create_store, and writes go through plain attribute or item assignment at any depth. Nested dicts wrap in writable proxies, and nested lists support append, insert, pop, remove, clear, and index assignment. Each write batches its notifications; use modify_mutable with produce or reconcile to group several changes into one update.

Parameters:

Name Type Description Default
initial Any

Initial dict state.

required

Returns:

Type Description
Any

A mutable reactive proxy.

Example
state = create_mutable({"count": 0, "user": {"name": "Ada"}, "tags": []})
create_effect(lambda: print(state.count, state.user.name))
state.count = 5             # effect re-runs
state.user.name = "Grace"   # nested write, effect re-runs
state.tags.append("new")    # list mutation, tracked

create_store

create_store(initial: Any) -> Tuple[Any, _StoreSetter]

Create a reactive store from an initial value.

Parameters:

Name Type Description Default
initial Any

Initial state. Dicts and lists are wrapped in reactive proxies; other values are returned unchanged.

required

Returns:

Type Description
Any

A tuple (store, set_store) where store is a reactive

_StoreSetter

proxy that tracks reads per-path, and set_store is a setter

Tuple[Any, _StoreSetter]

supporting path-based updates and

Tuple[Any, _StoreSetter]

produce batches.

Example
store, set_store = create_store({"count": 0, "user": {"name": "Ada"}})

store.count         # 0
store.user.name     # "Ada"

set_store("count", 5)
set_store("user", "name", "Jane")
set_store("count", lambda c: c + 1)

See the module docstring for the full set of supported calling conventions.

modify_mutable

modify_mutable(state: Any, modifier: Any) -> None

Apply a batched modification to a create_mutable proxy.

Matches SolidJS's modifyMutable. The modifier is either a produce draft function, a reconcile result, or a plain callable receiving a mutable draft (shorthand for produce). All resulting signal notifications flush once, as a single update.

Parameters:

Name Type Description Default
state Any

A proxy created by create_mutable (or any store proxy).

required
modifier Any

A produce(...) / reconcile(...) result, or a callable draft mutator.

required
Example
state = create_mutable({"a": 1, "b": 2})
modify_mutable(state, produce(lambda s: (
    setattr(s, "a", 10),
    setattr(s, "b", 20),
)))
modify_mutable(state, reconcile(fetched_state))

produce

produce(fn: Callable[..., None]) -> _ProduceResult

Create a producer for batch-mutating store state.

fn receives a mutable draft of the store. Mutations are recorded and applied reactively when the producer is passed to a store setter created by create_store.

The draft supports attribute access, item access, and append / pop for lists.

Parameters:

Name Type Description Default
fn Callable[..., None]

A function that mutates the supplied draft. The draft is consumed immediately when applied; don't keep a reference past the call.

required

Returns:

Type Description
_ProduceResult

A marker object recognized by the store setter.

Example
set_store(produce(lambda s: setattr(s, "count", s.count + 1)))

set_store(produce(lambda s: s.todos.append(
    {"text": "New", "done": False}
)))

reconcile

reconcile(data: Any, key: Optional[str] = 'id') -> _ReconcileResult

Diff external data into a store, keeping identity for unchanged items.

Matches SolidJS's reconcile. Pass the result to a store setter; instead of replacing the state wholesale, the incoming data is merged: dicts update key by key, and lists of dicts are matched by key so existing item objects are updated in place rather than replaced. Only the leaf signals whose values actually changed notify, and For rows for unchanged items keep their DOM.

Parameters:

Name Type Description Default
data Any

The incoming plain data (dict, list, or scalar).

required
key Optional[str]

Dict key used to match list items. Defaults to "id". Pass None to disable key matching (positional replace).

'id'

Returns:

Type Description
_ReconcileResult

A marker object recognized by the store setter.

Example
set_store("todos", reconcile(fetched_todos))

unwrap

unwrap(value: Any) -> Any

Return the raw data behind a store proxy (non-reactive).

Matches SolidJS's unwrap. Reading the result doesn't subscribe to anything; mutations to it bypass reactivity entirely.

Parameters:

Name Type Description Default
value Any

A store proxy (or any value).

required

Returns:

Type Description
Any

The underlying dict/list for proxies; value unchanged

Any

otherwise.

Fragment

Fragment(*args: Any) -> VNode

Group multiple children without adding an extra DOM wrapper element.

Fragments use empty comment nodes as start/end markers and mount their children directly into the parent container. This avoids extra elements that would pollute selectors like :first-child or affect layout.

Parameters:

Name Type Description Default
*args Any

Either a sequence of children (Fragment(a, b, c)) or a single dict containing a children key (the form used when Fragment is called as h(Fragment, {}, a, b, c)).

()

Returns:

Type Description
VNode

A _fragment VNode that the reconciler will mount inline.

Example
Fragment(h1("Title"), p("Body text"))
h(Fragment, {}, h1("Title"), p("Body text"))  # same thing

dynamic

dynamic(getter: Callable[[], Any], *, key: Optional[Union[str, int]] = None) -> VNode

Create a reactive-hole VNode that re-evaluates getter on dependency changes.

This is the explicit form of the same machinery that wraps callable children automatically. Use it when you want to be explicit about which child is dynamic, or to attach a stable key for keyed reuse inside a fragment.

The getter may return a VNode, a str, a list of either, or None.

Parameters:

Name Type Description Default
getter Callable[[], Any]

Zero-arg callable evaluated inside its own effect. Any signal reads inside the getter become dependencies that trigger re-evaluation.

required
key Optional[Union[str, int]]

Optional stable identity used by keyed reconciliation.

None

Returns:

Type Description
VNode

A _dynamic VNode that the reconciler will mount as a reactive hole.

Example
div(dynamic(lambda: f"Hello, {name()}!"))

h

h(tag: Optional[Union[str, Callable[..., Any]]], props: Optional[PropsDict] = None, *children: Any) -> VNode

Create a VNode from a tag, props, and children.

This is the low-level VNode constructor used everywhere. For common HTML tags, prefer the helpers in wybthon.html (div, span, button, …).

Callable children (zero-argument getters) are passed through unchanged; normalize_children wraps them as _dynamic VNodes when the parent element mounts. Components receive their children verbatim via the children prop so they can decide how to render them.

Parameters:

Name Type Description Default
tag Optional[Union[str, Callable[..., Any]]]

An HTML tag name ("div"), a special tag ("_text", "_dynamic", "_fragment"), or a component callable.

required
props Optional[PropsDict]

Mapping of prop names to values. May be None.

None
*children Any

Children to attach. Lists/tuples are flattened.

()

Returns:

Type Description
VNode

A new VNode.

Example
from wybthon import h

view = h("button", {"on_click": handle_click}, "Click me")

is_getter

is_getter(value: Any) -> bool

Return True when value is a zero-arg callable suitable for a reactive hole.

The check excludes:

  • VNode instances
  • Classes (isinstance(value, type))
  • Components and providers (marked with _wyb_component / _wyb_provider)
  • Ref objects (have a current attribute)
  • Callables that require positional arguments (e.g., event handlers taking an event object)

Parameters:

Name Type Description Default
value Any

Any value, typically a child or prop value being normalized.

required

Returns:

Type Description
bool

True if the value should be treated as a reactive getter.

ErrorBoundary

ErrorBoundary(props: Any) -> Any

Catch render errors in children and display a fallback.

Parameters:

Name Type Description Default
props Any

The component's props with the following keys:

  • fallback: A VNode, a string, or a callable (error, reset) -> VNode. The callable form may also accept just (error,).
  • on_error: Optional callback invoked with the caught exception (errors raised inside the callback are swallowed).
  • reset_key / reset_keys: When this value (or callable result) changes, the boundary auto-clears the current error.
  • children: Children rendered when no error is active.
required

Returns:

Type Description
Any

A reactive VNode subtree that swaps to the

Any

fallback whenever a child raises.

Portal

Portal(children: Union[VNode, List[VNode], None] = None, mount: Any = 'body') -> VNode

Render children into a different DOM container.

Matches SolidJS's <Portal mount={...}>. The children mount into mount (by default document.body) while remaining linked to the surrounding component's reactive scope, so signals, context, and lifecycle hooks still apply.

Parameters:

Name Type Description Default
children Union[VNode, List[VNode], None]

A single VNode or a list of them.

None
mount Any

The target container: an Element instance, a CSS selector string, or a kernel node id. Defaults to "body".

'body'

Returns:

Type Description
VNode

A component VNode whose children render inside mount.

Example
Show(
    when=show_modal,
    children=lambda: Portal(
        div(p("Modal content"), class_="modal"),
        mount="#modal-root",
    ),
)

render

render(vnode: VNode, container: Union[Element, str, int]) -> Element

Render a VNode tree into a container element.

Subsequent calls with the same container patch the existing tree in place; only the differences are applied. All emitted DOM ops are committed to the backend in one batch before this returns.

Parameters:

Name Type Description Default
vnode VNode

The root VNode to render.

required
container Union[Element, str, int]

An Element wrapper, a CSS selector string identifying an existing DOM node, or a kernel node id.

required

Returns:

Type Description
Element

The wrapped container Element. Useful for chaining or for

Element

retaining a reference to the mount point.

Example
from wybthon import h, render

render(h("h1", {}, "Hello, world!"), "#app")
Link(props: Any) -> Any

Anchor element component that navigates via the History API.

Wrapped in a reactive hole so the active class flips automatically when the route changes; no parent re-render is required. Modifier-key clicks (Cmd/Ctrl/Shift) and middle-clicks are passed through to the browser so users can open links in a new tab.

Parameters:

Name Type Description Default
props Any

The component's props with the following keys:

  • to (str): Target path. Joined with the active base path unless it starts with http://, https://, or #.
  • replace (bool): When True, replace the current history entry instead of pushing a new one.
  • class_active (str): Class added when to matches the current path. Defaults to "active".
  • base_path (str): Override for the base path. Defaults to the value provided by the surrounding Router.
  • class / class_ / className: Recognized class spellings, merged with the active class when applicable.
  • All other props are forwarded to the underlying <a> element.
required

Returns:

Type Description
Any

A reactive VNode for the anchor element.

Router

Router(props: Any) -> Any

Function component that renders the matched route's component.

The render function is wrapped in a reactive hole so that updates to current_path automatically re-evaluate the matched route; no parent re-render is required.

Parameters:

Name Type Description Default
props Any

The component's props with the following keys:

  • routes (List[Route]): Declared routes.
  • base_path (str): Base path stripped before matching.
  • not_found: Optional component rendered when no route matches. Falls back to a literal "Not Found" <div>.
required

Returns:

Type Description
Any

A reactive VNode containing the matched

Any

component, wrapped in a Provider that

Any

publishes the active base_path via

Any

navigate

navigate(path: str, *, replace: bool = False) -> None

Programmatically change the current path and update current_path.

Parameters:

Name Type Description Default
path str

Target URL path, including any query string.

required
replace bool

When True, use history.replaceState so the current history entry is overwritten instead of appended.

False

Suspense

Suspense(fallback: Any = None, children: Any = None) -> VNode

Show a fallback while resources read under the boundary are pending.

Parameters:

Name Type Description Default
fallback Any

VNode, string, or callable returning one of those. Shown while any registered resource is pending.

None
children Any

Children rendered when nothing is pending. Resources called anywhere in this subtree self-register with the boundary while they're in their initial "pending" state.

None

Returns:

Type Description
VNode

A component VNode that toggles between

VNode

fallback and children.

SuspenseList

SuspenseList(children: Any = None, reveal_order: str = 'forwards', tail: Optional[str] = None) -> VNode

Coordinate the reveal order of multiple Suspense boundaries.

Matches SolidJS's <SuspenseList>. Each Suspense boundary mounted underneath (that isn't nested inside another boundary) registers with the list in mount order, and the list decides when each may reveal its content and whether it shows its fallback.

Parameters:

Name Type Description Default
children Any

Children containing one or more Suspense boundaries.

None
reveal_order str

One of "forwards" (default; contents reveal top-to-bottom, each waiting for the ones before it), "backwards" (bottom-to-top), or "together" (all reveal at once when every boundary has loaded).

'forwards'
tail Optional[str]

Fallback policy for still-pending boundaries. None (default) shows every pending boundary's fallback, "collapsed" shows only the next fallback in reveal order, and "hidden" shows none.

None

Returns:

Type Description
VNode

A component VNode.

Example
SuspenseList(
    reveal_order="forwards",
    tail="collapsed",
    children=[
        Suspense(fallback=p("Loading A..."), children=[PanelA()]),
        Suspense(fallback=p("Loading B..."), children=[PanelB()]),
    ],
)
Note

A boundary whose content hasn't mounted yet doesn't start its resource fetches, so "forwards" reveals sequentially-loading content as a cascade rather than loading everything in parallel. Start fetches outside the boundaries (or pass resources down as props) when parallel loading matters.

Provider

Provider(props: Any) -> Any

Context provider component.

Renders its children transparently. The reconciler stores value as a Signal on this component's ownership scope so that descendants can find it via use_context and react to updates with fine-grained precision.

Children are wrapped in a reactive hole so updates from the parent (for example a router swapping the matched route component) flow into the subtree even though the provider body itself runs only once.

Parameters:

Name Type Description Default
props Any

The component's props with the following keys:

  • context (Context): The context being provided.
  • value: The current value to expose to descendants.
  • children: A VNode or list of VNodes rendered transparently.
required

Returns:

Type Description
Any

A reactive VNode subtree containing the

Any

provider's children.

create_context

create_context(default: Any) -> Context

Create a new Context with the given default value.

Parameters:

Name Type Description Default
default Any

Value returned by use_context when no provider is found above the consumer.

required

Returns:

Type Description
Context

A fresh Context token. Each call returns a context with a

Context

unique id, even when default is the same.

use_context

use_context(ctx: Context) -> Any

Read the current value for ctx from the ownership tree.

Walks up the owner chain looking for the nearest provider that stored a value for this context. The returned value is unwrapped from the provider's signal so callers always observe the current value. When invoked inside a tracking scope (a reactive hole or effect), the dependency on the provider signal is recorded so the scope re-runs whenever the provider updates.

Parameters:

Name Type Description Default
ctx Context

The context token created by create_context.

required

Returns:

Type Description
Any

The nearest provider's current value, or

Any

ctx.default when no provider exists above the caller.

Dynamic

Dynamic(component: Any = None, props: Optional[Dict[str, Any]] = None, **kwargs: Any) -> VNode

Render a dynamically-chosen component.

component may be a string tag name, a component function, or None (renders nothing). It can also be a getter for reactive switching.

Parameters:

Name Type Description Default
component Any

Tag name, component callable, getter, or None.

None
props Optional[Dict[str, Any]]

Optional dict of props forwarded to the resolved component.

None
**kwargs Any

Additional props (merged on top of props).

{}

Returns:

Type Description
VNode

A component VNode that re-mounts whenever

VNode

the resolved component identity changes.

Example
Dynamic(component=lambda: heading_level(),
        children=[f"Section {idx}"])

For

For(each: Any = None, children: Any = None, fallback: Any = None) -> VNode

Render a list of items using a per-item mapping function.

For(each=items,
    children=lambda item, index: li(item()))

Inside the callback, item is a signal-backed getter returning the current item value, and index is a signal-backed getter returning the current integer index, matching SolidJS <For>.

For is built on map_array: the mapping callback runs exactly once per unique item (keyed by reference identity), and the rendered subtree is cached. When the list changes, unchanged rows keep their DOM untouched; the reconciler only mounts additions, unmounts removals, and moves reordered rows. When an item leaves the list, its reactive scope (including any effects or cleanups created inside the callback) is disposed.

Parameters:

Name Type Description Default
each Any

List getter (typically a signal accessor) or plain list.

None
children Any

A (item_getter, index_getter) -> VNode callable.

None
fallback Any

Slot rendered when the list is empty.

None

Returns:

Type Description
VNode

A component VNode.

Index

Index(each: Any = None, children: Any = None, fallback: Any = None) -> VNode

Render a list by index with a stable item getter.

Unlike For, the children callback receives (item_getter, index) so that the DOM subtree for each index is reused even when the underlying data changes.

Index is built on index_array: each slot renders once and owns a signal-backed item_getter that updates when the value at that position changes. Growing the list creates and mounts new slots; shrinking disposes and unmounts excess slots.

Parameters:

Name Type Description Default
each Any

List getter (typically a signal accessor) or plain list.

None
children Any

A (item_getter, index: int) -> VNode callable.

None
fallback Any

Slot rendered when the list is empty.

None

Returns:

Type Description
VNode

A component VNode.

Match

Match(when: Any = None, children: Any = None) -> _MatchResult

Declare a branch inside a Switch.

when may be a getter or a plain value:

Match(when=lambda: x() > 0, children=lambda: p("positive"))

Must be used inside Switch().

Parameters:

Name Type Description Default
when Any

Predicate value or zero-arg getter.

None
children Any

A VNode, a callable returning a VNode, or a plain value to coerce to text.

None

Returns:

Type Description
_MatchResult

An opaque branch descriptor consumed by Switch.

Show

Show(when: Any = None, children: Any = None, fallback: Any = None) -> VNode

Conditionally render children when when is truthy.

Show(when=count, children=lambda: p("Count: ", count),
     fallback=lambda: p("Empty"))

Behavior:

  • when may be a zero-arg getter or a plain value.
  • children / fallback may be a VNode, a callable, or a plain value. When children is callable and when is truthy, the truthy value is passed as the first argument (matching SolidJS <Show>).

The component creates a keyed conditional scope: when the truthiness of when changes, the previous branch's scope is disposed and a new scope is created. This ensures that effects and cleanups registered inside a branch are properly torn down on transitions.

Parameters:

Name Type Description Default
when Any

Condition value or zero-arg getter.

None
children Any

Slot rendered when the condition is truthy.

None
fallback Any

Slot rendered when the condition is falsy.

None

Returns:

Type Description
VNode

A component VNode that re-renders when the

VNode

condition's truthiness changes.

Switch

Switch(*branches: _MatchResult, fallback: Any = None) -> VNode

Render the first matching Match branch, or fallback.

Switch(
    Match(when=lambda: status() == "loading",
          children=lambda: p("Loading...")),
    Match(when=lambda: status() == "ready",
          children=lambda: p("Ready")),
    fallback=lambda: p("Unknown"),
)

Each Match when is evaluated lazily inside the Switch component's reactive scope.

Parameters:

Name Type Description Default
*branches _MatchResult

One or more Match results, in priority order.

()
fallback Any

Slot to render when no branch matches. May be a VNode, a callable, or a plain value.

None

Returns:

Type Description
VNode

A component VNode for the first matching

VNode

branch, or the fallback slot.

Public API (top-level imports)

  • Core rendering
  • Element, Ref
  • VNode, h, render, Fragment, dynamic, is_getter
  • Components
  • component, forward_ref, ErrorBoundary, Suspense
  • Reactivity
  • create_signal (optional equals=; the setter also accepts an updater function), create_effect, create_render_effect, create_computed, create_memo, create_deferred, batch, untrack, on, create_root, create_selector
  • on_mount, on_cleanup, create_unique_id, catch_error
  • ReactiveProps, get_props, children (memoized children helper), get_owner, run_with_owner
  • Resource, create_resource
  • merge_props, split_props, map_array, index_array
  • Types: Signal, Computed (for type hints; create instances via create_signal / create_memo)
  • Context
  • Context, create_context, use_context, Provider
  • Stores
  • create_store, create_mutable, produce, reconcile, unwrap
  • Flow control
  • Show, For, Index, Switch, Match, Dynamic
  • Router
  • Route, Router, Link, navigate, current_path
  • Forms
  • State and validation: FieldState, form_state, validate, validate_field, validate_form
  • Validators: required, min_length, max_length, email
  • Bindings and submit helpers: bind_text, bind_checkbox, bind_select, on_submit, on_submit_validated
  • A11y helpers: a11y_control_attrs, error_message_attrs
  • Events
  • DomEvent
  • Lazy loading
  • lazy
  • Development mode
  • DEV_MODE, set_dev_mode, is_dev_mode

Browser vs non-browser

DOM/VDOM rendering (Element, render, router, etc.) requires a Pyodide/browser environment. In non-browser contexts the reactivity primitives, stores, forms, context, flow control, and pure-Python VDOM constructs (VNode, h, Fragment, dynamic, is_getter) are still available.