Skip to content
Alberto Ruiz edited this page Apr 17, 2026 · 3 revisions

HTeaLeaf introduces a reactive state layer inspired by modern frontend frameworks.
It allows you to define global or user-specific state directly in Python, and bind it to HTML components that update automatically when the state changes.

HTeaLeaf includes a full server-driven reactivity system built around three components:

  • Store: Global shared state
  • AuthStore: Per-user state bound to sessions
  • SuperStore: The orchestrator that connects and synchronizes stores through HTTP and JavaScript

What is a Store?

A Store is a shared, reactive state container that lives on the server side and synchronizes with the client through HTeaLeaf’s reactivity engine.

from HTeaLeaf.State.Store import Store

cstore = Store({"counter": 1})

Each Store behaves like a reactive dictionary you can read and modify values, and any UI elements bound via .react() automatically update when the data changes.

Navigating store paths

HTeaLeaf stores can be accessed using path-like keys, similar to JSON pointers. This allows deep updates inside nested data structures such as lists or dictionaries.

For example:

store = Store({"todo": [{"value": "Buy milk", "done": False}]})

This is used by the JavaScript JSCode helper:

store.js.update("todo/0/done", True)

Example: Reactive counter

@app.route("/counter")
def counter():
    return div(
        rButton("-").attr(onclick=cstore.do.update("counter", -1)),
        h3(cstore.react("counter")),
        rButton("+").attr(onclick=cstore.do.update("counter", 1)),
    )

AuthStore: per-user reactive state

AuthStore behaves just like Store, but each user session has its own isolated copy.

from HTeaLeaf.Magic.Store import AuthStore
from HTeaLeaf.Server.Server import Session

def auth_session(session: Session):
    if session.has("userName"):
        return session["userName"]
    return None

todoStore = AuthStore(auth_session, {"todo": []})

Each authenticated user gets their own instance of the todo data, independent from others.

@app.route("/")
def home(session):
    if not session.has("userName"):
        return redirect("/login")

    return div(
        [elementoCompra(idx, t) for idx, t in enumerate(todoStore.auth(session).read("todo"))],
        button("Add Task").attr(onclick=JSCode(todoStore.do.set("todo", {"done": false, "value": val}))
    )

Each logged-in user interacts with their own store content, persisted in memory and linked to their session ID.

SuperStore: the orchestrator

SuperStore acts as the reactivity controller for all stores. It connects them to the app and automatically registers endpoints for synchronization and data mutation.

from HTeaLeaf.State.Store import SuperStore
from HTeaLeaf.Server.WSGI import WSGI

app = WSGI()
SuperStore(app)

Once initialized:

  • All Store and AuthStore instances become discoverable.
  • The framework exposes internal HTTP endpoints for reading and writing store data.
  • The Store.js objects (injected into the frontend) communicate with these endpoints.

You typically only need one SuperStore per application.

How SuperStore works

When the client triggers an update, like:

store.do.update("todo/0/done", True)

translated in the frontend to:

store_xyz.update("todo/0/done", true)

the call is routed to an automatically exposed backend endpoint, typically something like

POST /api/_store/{api_id}/todo/0/done

SuperStore:

  1. Parses the path (todo/0/done).
  2. Locates the right Store or AuthStore instance.
  3. Applies the mutation.

This allows fully reactive data flow over plain HTTP, no WebSockets required.

Example: Complete setup

from HTeaLeaf.Magic.Store import SuperStore, Store, AuthStore
from HTeaLeaf.Server.Server import Session
from HTeaLeaf.Server.WSGI import WSGI

app = WSGI()
SuperStore(app)  # register the orchestrator

globalStore = Store({"counter": 0})

def auth_session(session: Session):
    return session["userName"] if session.has("userName") else None

todoStore = AuthStore(auth_session, {"todo": []})

After this, globalStore and todoStore are automatically exposed and reactive.

Data flow summary

+-------------+       +----------------+       +---------------+
|  Python App | <---> |  SuperStore    | <---> |  Client (JS)  |
+-------------+       +----------------+       +---------------+
       ▲                       ▲                        ▲
       |                       |                        |
       |     Store updates     |   HTTP fetch/update    |
       |-----------------------|------------------------|
  • SuperStore handles orchestration, routing, and propagation.
  • Store / AuthStore define the reactive data models.
  • JSDO translates Python actions into client-side JS that calls the correct store endpoints.

Clone this wiki locally