Skip to content

tempestweb 🌩️

Build web apps in typed Python. One declarative widget tree, a DOM renderer, and three execution modes that share 100% of the application code.


tempestweb is a framework for building web apps by writing typed Python. You describe the UI as a declarative tree of widgets in a view() function, and the framework renders it to the DOM. The same view(), without changing a line, runs in three execution modes:

  • Mode A — WASM


    Your Python runs in the browser via Pyodide. Like PyScript. Fully offline after the initial load.

    When to use: full offline, zero server infra, fast prototyping.

  • Mode B — Server


    Your Python runs on the server (FastAPI) and talks to a thin JS client over WebSocket or SSE. Like Phoenix LiveView.

    When to use: server-side logic, central state, live data.

  • Mode C — transpile


    The app layer is transcribed to native JavaScript at build time. Zero Python in the browser — a static bundle any CDN can serve.

    When to use: installable PWA, great SEO and first-paint, zero server cost.

The trick: the app never names a transport. The very same examples/counter/app.py runs under --mode wasm, --mode server and --mode transpile without changing a line. 🚀

Which mode should I pick?

  • Need SEO, fast first-paint, and a static server-free bundle? → Mode C (transpile) — the default choice for public sites/PWAs.
  • Need to keep logic or state on the server (live data, secrets)? → Mode B (server).
  • Want live Python in the browser to prototype or run Python libs client-side? → Mode A (WASM).

You never decide this in code — only at build --mode time. Start with the Tutorial, which runs the counter in all three modes.

Not a front-end developer? Start with the ready-made screens

If what you need is an admin panel, a dashboard, a CRUD screen with search and pagination, a settings form or a login screen, you do not have to learn layout, CSS or a single breakpoint.

The ready-made screens (presets) take typed data — which entries the menu has, which numbers the dashboard shows, which columns the table has — and decide the appearance for you. The result is already responsive: the sidebar becomes a drawer on a phone, the cards reflow, the table scrolls.

admin_shell(
    title="Console ACME",
    nav=[NavItem("Overview", "overview"), NavItem("Users", "users")],
    active=app.state.tab,
    on_navigate=go_to,
    body=dashboard_page(
        title="Overview",
        kpis=[Kpi("Revenue", "R$ 82,400", delta="+12%", tone="success")],
    ),
)

A whole panel comes out in ~260 lines of Python, with no hand-written Style — see the full Admin Console.

How it works

   view(app) ──build──▶ Node tree (IR)        ← shared core
                          diff
                        [ Patch ]              insert / remove / update / reorder / replace
                    ╱        │        ╲
          Mode A          Mode B          Mode C
       (pyodide.ffi)   (WebSocket/SSE)  (app → native JS, diff in JS)
                    ╲        │        ╱
                  client/ (pure JS): apply patches to the DOM
                  + Style→CSS + event capture     ← same code in all three modes

The view() function produces a widget tree (IR). The reconciler diffs the old tree against the new one and emits patches — plain serialized data. In Modes A and B the diff runs in Python and patches travel over a transport; in Mode C the app layer is transcribed to JS, so the diff runs natively in the browser. In all of them the JS client only knows how to consume a patch and mutate the DOM — it does not care where the patch came from. That is why the renderer is the same across all three modes.

Where to start

Head straight to Installation and then follow the Tutorial — the Counter. In four short pages you build the canonical app and understand the wire contract end to end.

What you will find here

Language

This documentation is bilingual. Use the language selector at the top of the page to switch between Português (Brasil) and English (US).

Relationship to tempestroid

tempestweb is the web sibling of tempestroid, the mobile framework in the same family. Both follow the "one tree, multiple renderers" philosophy and share the same renderer-agnostic core — the tempest-core package (IR, diff/patch, state, style, widgets and the Material 3 component catalog, which tempestweb re-exports under tempestweb.components — see Ready-made components). tempestroid renders to native screens; tempestweb renders to the DOM. If you already know one, the mental model transfers directly — but you don't need to know tempestroid to use tempestweb.

Next step

  1. Install it — one command.
  2. Build the counter — four pages, and you understand the whole cycle.
  3. After that, follow wherever your problem is: assemble the screen with presets, or go straight to security and deploy if the app already exists.

Project conventions

Python: double quotes, full typing (mypy --strict), Google docstrings in English, async-first. Client: plain JavaScript — no TypeScript, no framework, no build step.

Project status

All three modes are functional today — the counter and the 40-plus examples in the gallery build, render, and pass the full gate. The living design docs are still versioned in the repository: plan.md, roadmap.md and contract.md. This documentation reflects the surface already built and links to the plans for full detail.