Skip to content

synstate-dom

The UI library for SynState. Pass its observables straight into JSX. Your component runs once, and after that only the attributes, properties and text you bound to an observable change. No compiler, no virtual DOM.

Made for SynState

synstate-dom is the UI library that connects most directly to SynState’s runtime: the graph ends in the DOM, with nothing converted on the way. In SynState’s benchmark summary, SynState stays within 2.7× of the fastest library in every scenario: the only library measured in all of them whose worst case stays in single digits.

Simple, and rarely slow

One way to write each thing, rather than extra forms that only win a row of a benchmark. On the operations of js-framework-benchmark, its slowest operation takes 1.56× the fastest library’s time: behind Solid, Preact and Preact + Signals, and well ahead of React’s 3.79×.

Fine-grained, called once

Your component function is called once, when it mounts. After that, an update travels through the synstate graph and writes straight to the one DOM leaf bound to it: an attribute, a property or a text node.

No compiler

All you need is TypeScript’s standard "jsx": "react-jsx" and jsxImportSource. There is no Babel or Vite plugin to configure.

Reactivity in the types

Wherever JSX takes data, you pass an observable or a constant(...), never a plain value. So if you read a snapshot by mistake, you get a type error instead of a view that silently stops updating. And a prop holds the bindable itself, not a value read from it, so you can destructure props or give them defaults without breaking anything.

No leaks by construction

If, Match and For each mount what they show in a scope of their own. Close a branch or remove a row, and every derivation and subscription made inside it goes away with it.