Skip to content

Flow control

wybthon.flow

flow

SolidJS-style reactive flow control components.

These components create isolated reactive scopes so that only the relevant subtree re-renders when the tracked condition or list changes.

Each flow control is implemented as a proper function component (returning dynamic(...)) rather than a plain helper. Conditions, sources, children, and fallbacks are accepted as getters (zero-arg callables) so that reads happen inside the flow control's own reactive effect, not the parent's.

API rules:

  • when / each: pass a getter (the signal accessor itself) or a raw value. Getters are called inside the flow control's own scope.
  • children: may be a VNode, a callable returning a VNode, or (for For / Index) the per-item mapping callback.
  • fallback: same flexibility as children.

Fine-grained list primitives:

  • For maintains stable per-item reactive scopes (keyed by reference identity); the mapping callback runs only once per unique item.
  • Index maintains stable per-index scopes with a reactive item signal that updates when the value at that position changes.
Example
Show(when=is_logged_in,
     children=lambda: p("Welcome!"),
     fallback=lambda: p("Please log in"))

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

Functions:

Name Description
Show

Conditionally render children when when is truthy.

For

Render a list of items using a keyed mapping function.

Index

Render a list by index with a stable item getter.

Match

Declare a branch inside a Switch.

Switch

Render the first matching Match branch, or fallback.

Dynamic

Render a dynamically-chosen component.

Show

Show(props_or_when: Any = None, children_pos: Any = None, /, **kwargs: Any) -> Any

Conditionally render children when when is truthy.

Can be called in two styles:

Component style (reactive; recommended for dynamic conditions):

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

Direct call (evaluated once; fine inside an explicit hole):

Show(when=lambda: count() > 0,
     children=lambda: p("Positive"),
     fallback=lambda: p("Not positive"))

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
props_or_when Any

A props dict (component style) or the when value (direct call form).

None
children_pos Any

Positional children slot (direct call form).

None
**kwargs Any

when, children, and optional fallback.

{}

Returns:

Type Description
Any

A reactive VNode tree that re-renders when

Any

the condition's truthiness changes.

For

For(props_or_each: Any = None, children_pos: Any = None, /, **kwargs: Any) -> Any

Render a list of items using a keyed mapping function.

Component style (reactive):

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

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 maintains stable per-item reactive scopes keyed by reference identity. The mapping callback runs only once per unique item. When an item leaves the list, its scope (including any effects or cleanups created inside the callback) is disposed.

Parameters:

Name Type Description Default
props_or_each Any

A props dict (component style) or the each getter / list (direct call form).

None
children_pos Any

Positional children callback (direct call form).

None
**kwargs Any

each, children (a (item, index_getter) -> VNode callable), and optional fallback.

{}

Returns:

Type Description
Any

A reactive VNode tree that diffs the list by

Any

item identity.

Index

Index(props_or_each: Any = None, children_pos: Any = None, /, **kwargs: Any) -> Any

Render a list by index with a stable item getter.

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

Index maintains stable per-index reactive scopes. Each slot has a signal-backed item_getter that updates when the value at that position changes. Growing the list creates new scopes; shrinking disposes excess scopes.

Parameters:

Name Type Description Default
props_or_each Any

A props dict (component style) or the each getter / list (direct call form).

None
children_pos Any

Positional children callback (direct call form).

None
**kwargs Any

each, children (a (item_getter, index: int) -> VNode callable), and optional fallback.

{}

Returns:

Type Description
Any

A reactive VNode tree that diffs the list by

Any

index.

Match

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

Declare a branch inside a Switch.

when may be a getter or a plain value. Supports both positional and keyword calling styles:

Match(True, h("p", {}, "yes"))                                # positional
Match(when=lambda: x() > 0, children=lambda: p("positive"))   # keyword

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
**kwargs Any

Same keys as the explicit parameters; takes priority over positional values when provided.

{}

Returns:

Type Description
_MatchResult

An opaque branch descriptor consumed by Switch.

Switch

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

Render the first matching Match branch, or fallback.

Component style (reactive):

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 Any

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
**kwargs Any

Optional fallback override.

{}

Returns:

Type Description
Any

A reactive VNode for the first matching

Any

branch, or the fallback slot.

Dynamic

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

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
Any

A reactive VNode that re-mounts whenever

Any

the resolved component identity changes.

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

What's in this module

flow provides SolidJS-style reactive flow control components. They create isolated reactive scopes so that only the relevant subtree re-renders when the tracked condition or list changes.

Component Use it for
Show Conditional rendering with a single fallback.
For Keyed list rendering with stable per-item scopes.
Index Index-keyed list rendering with reactive item signals.
Switch / Match Multi-branch conditional rendering.
Dynamic Render a component chosen at runtime.

Idioms

from wybthon import (
    For, Index, Match, Show, Switch, component, create_signal,
)
from wybthon.html import li, p, ul


@component
def Demo():
    items, _ = create_signal(["a", "b", "c"])
    is_logged_in, _ = create_signal(False)

    return ul(
        Show(
            when=is_logged_in,
            children=lambda: li("Welcome!"),
            fallback=lambda: li("Please log in"),
        ),
        For(each=items, children=lambda item, idx: li(item(), key=idx())),
    )
  • Pass getters (the signal accessor itself) to when / each.
  • children may be a VNode, a callable returning a VNode, or the per-item mapping callback for For / Index.

See also