Supastate
Tiny reactive primitives for vanilla JS
Install from npm ↗Not every page needs a framework. Supastate is a tiny reactive engine for plain HTML and vanilla JavaScript, for the pages where pulling in a full framework would be the heaviest part of the site.
<script type="module">
import { reactive, text } from 'https://cdn.jsdelivr.net/npm/supastate/dist/index.mjs'
const state = reactive({ count: 0 })
text('#counter', () => state.count)
document.getElementById('increment').onclick = () => state.count++
</script>
That is the whole model. No virtual DOM, no components, no template syntax, no magic HTML attributes; just JavaScript functions that keep the exact DOM nodes affected by a change in sync with your state.
The entire engine is about 2.3 kB minified, roughly 1 kB gzipped over the wire. There is no build step: drop it in via CDN or install from npm. It works alongside Rails, Laravel, Django, HTMX, Astro, or nothing at all.
Everything cleans up after itself. Bindings and effects return a stop function, and computed values and resources have detach(), so widgets can mount and unmount without leaking subscriptions.
npm install supastate
Make state reactive
Wrap a plain object with reactive(). Mutations to any nested property are tracked automatically, arrays included.
Derive and react
effect() runs immediately and re-runs whenever a value it reads changes. computed() gives you lazy derived values that collapse intermediate changes into a single re-run.
Bind the DOM
text, attr, classList, and style keep individual nodes in sync. classList toggles single classes without touching whatever your HTML or CSS framework already put on the element.
Handle async
resource() tracks data, loading, and error reactively; it re-fetches when its dependencies change, supports polling, and discards stale responses.