Two questions this page answers: what do I have to unlearn? and why would I pick this over Solid?
Coming from React#
If you know React, you already know most of FormaJS. Components are functions. Props flow down. You import, export and compose the same way. The difference is how reactivity works — and it is simpler.
React re-runs your component function on every state change, diffs a virtual DOM, and patches the real one. FormaJS runs each component once. Signals update only the specific DOM nodes that read them. Keyed lists reconcile rows, while signal bindings update text and attributes without re-running the component.
| React | FormaJS | What changes |
|---|---|---|
useState | createSignal | [getter, setter] tuple; read with count() |
useMemo | createComputed | No dependency array — auto-tracks |
useEffect | createEffect | No dependency array — auto-tracks |
useReducer | createReducer | Same dispatch pattern |
useContext | createContext / inject | Same provider pattern |
React.memo | not needed | Components already run once |
| Component functions | same | function Counter(props) { … } |
| Props | same | <Counter count={count} /> |
| Children | same | Rest params or props.children |
| Import / export | same | Standard ES modules |
The one habit to break. In React, {count} in JSX is a value that a
re-render refreshes. Here there is no re-render, so a bare value is written
once and never again. Reactivity comes from passing a function:
<p>{count()}</p> // ❌ reads once at creation, never updates
<p>{() => count()}</p> // ✅ re-runs when count changes
<div class={() => cls()}>…</div> // ✅ same rule for propsThat single rule explains most "why is my UI not updating" questions. See
API.md for the full h() contract.
How is this different from Solid?#
FormaJS shares Solid's core insight — fine-grained signals updating the real DOM without a virtual DOM. If you know Solid, you will feel at home.
The differences are in scope and delivery. FormaJS adds islands hydration without a meta-framework, CSP compliance without a build step, three entry points (CDN script tag, hyperscript, JSX) sharing one signal graph, and a Rust SSR path that removes Node.js from the server. Solid gives you a mature JavaScript ecosystem: routing, a meta-framework (SolidStart), devtools and community component libraries.
Choose FormaJS when you want islands baked in, CSP safety out of the box, a Rust backend without a Node.js sidecar, or a CDN-first starting point that scales to a full compiled pipeline.
Choose Solid when you want a mature JS ecosystem, SolidStart for full-stack JS, community devtools, and your backend is already Node.js.
What FormaJS is not#
It is not a framework with opinions about routing, data fetching or state management. It is a reactive DOM library — you bring the architecture. The pieces that are opinionated (the compiler, the build pipeline, the Rust server) are separate packages you add when you want them; see the stack architecture.