Reactive HTML templating. Bind state to DOM via : attributes. No build step.
Full API in readme.md.
| File |
Role |
sprae.js |
Main entry. Registers directives, modifiers, default compiler. |
core.js |
Engine: sprae(), parse, use, decorate, frag, start, symbols. |
signal.js |
Built-in signals (preact-compatible API). |
store.js |
Reactive proxy store. Props → signals. Arrays, getters, methods. |
directive/ |
One file per directive. _.js = default (any attribute). |
test/ |
test.js entry, directive/ per-directive, modifier.js, mods.js. |
types/ |
Generated .d.ts (via npm run types). |
readme.md |
Full docs (single-page reference). API changes must be reflected here. |
npm run test:base # run tests (default signals + compiler)
npm run test # run tests with all signal/compiler combos
npm run build # esbuild bundle → dist/
npm run types # generate types/ from JSDoc
import sprae, { store, signal, effect, computed, batch, untracked, start, use, throttle, debounce, dispose } from 'sprae'
import sprae from 'sprae/core' // bare engine (no directives/modifiers registered)
import store from 'sprae/store'
import { signal, effect, computed, batch, untracked } from 'sprae/signal'
| Symbol |
Purpose |
_state |
Element's reactive state store |
_dispose |
Dispose function (= Symbol.dispose) |
_on / _off |
Enable/disable element effects |
_add |
Init child element (walk + apply directives) |
_signals |
Store's internal signals map |
_change |
Store's key-count tracking signal |
- Attribute order matters:
:each before :text, not after.
this refers to current element in expressions.
class is reserved — use cls as variable name.
_-prefixed store props are untracked (not reactive).
data- prefix eats all data-* attrs — use spread :="{ src: url }" for ambiguous names.
- Only valid HTML self-closing tags (
<input />, not <div />).
- Modifiers work on any directive (
:text.once, :fx.debounce-300), not just events.
- FOUC prevention:
<style>[\:each],[\:if],[\:else] {visibility: hidden}</style>.