spræ

DOM microhydration

Reactive sprinkles for HTML/JSX

<div :scope="{ q: '', items: ['Apple', 'Apricot', 'Banana', 'Cherry', 'Date', 'Elderberry'] }">
  <input :value="q" placeholder="Search fruits..." />
  <ul>
    <li :each="item in items.filter(i => i.includes(q))" :text="item"></li>
  </ul>
</div>

Principles

HTML-native
Keep existing HTML.
Standard JS expressions.
No build step, no config.
Open state
Controllable. ESM-first.
Preact signals enabled.
Sandboxed. Safe eval.
5kb, 0 deps
CDN <script> or npm i.
Any backend, any template, +JSX.
No ecosystem lock-in.

Usage Docs →

Copy and paste the following HTML into your page to load and sprae the page.

<script src="//unpkg.com/sprae" data-start></script>

Download sprae.js and import as ESM:

<script type="module">
  import sprae from './sprae.js'

  sprae(document.getElementById('app'), initState)
</script>

Reference API →

directive description example
:text Set text content <span :text="name">
:html Set innerHTML <div :html="content">
:class Set classes <div :class="{active: true}">
:style Set styles <div :style="{color:'#fff'}">
:value Bind input value <input :value="text">
:<prop> Set any attribute <a :href="url">
:hidden Toggle visibility <div :hidden="!show">
:if :else Conditional render <div :if="cond">
:each List render <li :each="item in list">
:scope Define state <div :scope="{x:1}">
:ref Get element ref <input :ref="el => {...}">
:fx Run effect <div :fx="log(x)">
:on<event> Event listener <button :onclick="fn()">
modifier description example
.once Run once :onclick.once="..."
.prevent Prevent default :onclick.prevent="..."
.stop Stop propagation :onclick.stop="..."
.window .document .self Change target :onkeydown.window
.away Click outside :onclick.away
.debounce .throttle .delay Timing control :oninput.debounce-300
.passive .capture Listener options :onscroll.passive
.enter .esc .ctrl Key filters :onkeydown.enter

FAQ All questions →

What is it?
A ~5kb script that adds reactivity to HTML via :attribute="expression" directives. No build step, no new syntax — just HTML and JS you already know. Can be seen as an alternative species to Alpine.js or petite-vue.
When to use it?
Adding interactivity to server-rendered pages, static sites, prototypes, or anywhere a full framework is overkill. Works with any backend.
How does it compare?
3× lighter than Alpine, faster in benchmarks. Uses signals (emerging standard) instead of custom reactivity. Full comparison.
Does it work with React/Next.js?
Yes. Sprae can inject into JSX for server components to avoid client components overhead.
How to handle components?
Manage duplication with templates/includes, or use web components.
Is it production-ready?
3+ years, 12 major versions, 1.5k+ commits. Full TypeScript support. Roadmap.