Skip to content

Coming from React

The component/state model is React's. The language and element syntax change.

React/JSX PyReact Forge
function App(props) { ... } @component on def App(...)
<Button label="Save" /> Button(label="Save") or h(Button, label="Save")
<div className="card"> html.div(..., class_="card")
onClick={() => ...} on_click=lambda: ...
useState, useEffect use_state, use_effect
items.map(item => <Row key={item.id}/>) A Python list comprehension with key=
createContext / provider create_context / context.provide(..., value=...)

Preserve React's rules

Call hooks at the top level of the component or a custom hook. Keep render pure. Treat props and state as snapshots; create a new list/dict/object for updates. Use stable keys for list items. Clean up subscriptions in effects.

Python components must be synchronous. For async data, use a stable resource with Suspense rather than async def App. Browser event handlers may be async.

Understand the interop boundary

Python component props preserve Python objects. Registered JavaScript components receive native JS arrays/objects. Browser events, DOM nodes and refs can be JS proxies: read str(event.target.value) when you want an ordinary Python string.

React's scheduler is real, but a long synchronous Python function still occupies the main thread until it returns. There is no Python React Compiler, complete ESLint-equivalent hook analysis or state-preserving Fast Refresh in this alpha.

The optional router is intentionally small; it does not claim React Router loader, nested-route or framework-mode compatibility.

Next: state, async data, or the compatibility matrix.