Component
wybthon.component¶
component
¶
@component decorator and forward_ref for function components.
Wybthon's component model is fully reactive and runs once:
- The body of an
@componentfunction executes a single time when the component mounts. - Each parameter declared in the function signature receives a reactive accessor (a zero-argument callable). Calling the accessor returns the current prop value and tracks it as a reactive dependency.
- Embedding an accessor directly inside a
VNodetree turns the surrounding region into a fine-grained reactive hole that updates only the relevant DOM when the prop changes. - The decorator also enables a direct call style: invoking the
component with keyword arguments yields a
VNodeinstead of running the body, so trees can be authored ergonomically.
Authoring modes:
- Named accessor mode: used when the signature has zero args, kwargs
with defaults, or
**kwargs. Each parameter becomes a reactive accessor for the prop of the same name. - Proxy mode: used when the signature has exactly one positional-only
or positional-or-keyword parameter with no default and no
*args/**kwargs. The single parameter receives the fullReactivePropsproxy.
Example
A trivial greeting and a counter::
@component
def Greet(name="world"):
return p("Hello, ", name, "!")
@component
def Counter(initial=0):
# ``untrack`` snapshots the seed value without subscribing
# (otherwise we would re-seed on every parent update, and
# dev mode would warn about a destructured prop).
count, set_count = create_signal(untrack(initial))
return div(
p("Count: ", count),
button("+", on_click=lambda e: set_count(count() + 1)),
)
When you need the underlying ReactiveProps proxy (e.g., to iterate
keys or forward unknown props), call
get_props from inside the component
body, or declare the component with a single positional parameter
(proxy mode).
Components are expected to return a VNode. Use
dynamic for explicit reactive holes when an entire
subtree needs to swap based on a signal. A callable return is also
accepted (it is wrapped in a single-root reactive hole) but the
canonical style is "return a VNode and embed dynamic(...) where you
need reactive swaps".
Functions:
| Name | Description |
|---|---|
component |
Decorate a function as a Wybthon component. |
forward_ref |
Create a component that forwards a |
component
¶
Decorate a function as a Wybthon component.
The body of fn is invoked once per mount. Each declared parameter
is bound to a reactive accessor: call it to read the current
value (tracked) or pass it directly into a VNode tree to create a
reactive hole.
The decorated callable also supports a direct call style:
Counter(initial=5) returns a VNode (equivalent to
h(Counter, {"initial": 5})) so component composition feels natural.
See the module docstring for the complete authoring guide and the full mode-selection table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[..., Any]
|
The function to decorate. Its signature determines whether named-accessor mode or proxy mode is used. |
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A wrapped callable. When called by the reconciler with a single |
Callable[..., Any]
|
props dict, it executes |
Callable[..., Any]
|
when called by user code with kwargs, it returns a |
forward_ref
¶
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 |
required |
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
A component callable that forwards the |
@component¶
Decorator that turns a function into a Wybthon component with fully-reactive props.
Each parameter is a reactive accessor, a zero-arg callable.
- Pass it directly into the tree to create a reactive auto-hole.
- Call it (
name()) to read the current value (tracked when called inside an effect or hole). - Wrap with
untrackfor a snapshot read.
from wybthon import component, p
@component
def Greeting(name="world"):
# ``name`` is a getter; passing it as a child becomes a reactive hole.
return p("Hello, ", name, "!")
Stateful components create signals during setup and embed reactive
holes (signal getters or dynamic(lambda: ...)). The body runs once;
seed local state from props using untrack:
from wybthon import component, create_signal, div, p, span, untrack
@component
def Counter(initial=0):
count, set_count = create_signal(untrack(initial))
return div(p("Count: ", span(count)))
Children is a normal prop, also a reactive accessor. Most
layouts read children once at setup; wrap with untrack:
from wybthon import component, h3, section, untrack
@component
def Card(title="", children=None):
kids = untrack(children) if callable(children) else children
if kids is None:
kids = []
if not isinstance(kids, list):
kids = [kids]
return section(h3(title), *kids, class_="card")
For memoized, reactive resolution of children (Solid-style), use the
children(fn) helper with get_props(). See Reactivity.
Direct calls with keyword arguments return a VNode:
The component still works with h():
Proxy mode¶
When the component declares a single positional parameter with no
default, the decorator passes the underlying ReactiveProps proxy
directly:
@component
def DumpProps(props):
# ``props.x`` -> reactive accessor; ``props.x()`` -> current value.
return p(dynamic(lambda: ", ".join(sorted(list(props)))))
Use get_props from inside any kwarg-style component
to obtain the same proxy.
forward_ref¶
forward_ref(render_fn) creates a component that receives a ref prop
and forwards it to a child element.
The wrapped function receives (props, ref) instead of (props,),
and ref is stripped from props (matching React's forwardRef
semantics).