I've built Grains.js. Grains.js is a lightweight framework that brings reactivity and state management to vanilla HTML, similar to Alpine.js and HTMX, but with built-in state tracking. Grains.js uses directives as a declarative approach and pure functions for state changers.
Getting Started
First, you need to include Grains.js into your page:
<span class="na">src="https://mk0y.github.io/grains.js/dist/grains.min.js"
>
To define state in Grains.js, you use the g-state
directive. This automatically initializes a reactive state that can be referenced throughout your HTML.
Example: Counter with Reactive State
g-state="counter" g-init='{"count": 0}'>
Count: g-text="count">
g-on:click="increment">Increment
g-on:click="decrement">Decrement
How It Works
Define state: The
g-state="counter"
initializes a state variable called counter. This creates a global variablecounter
. If you inspect it in console aswindow.counter
you'll see its value asProxy(Object) {count: 0}
. Whereaswindow.counter.count
is equal to zero.Set initial value: The
g-init='{"count": 0}'
assigns an initial value. This can also be likeg-init="myCount"
, which is referenced to a global variablewindow.myCount
that you have to create.Bind state to elements: The
updates dynamically when counter changes.
Modify state with events: The
g-on:click="increment"
updates the state on button click.
Define State Changers
State changes are immutable and to dispatch the change we only create global pure functions. In our case increment
is a global pure function, which you can inspect as window.increment
.
To dispatch the change we use .set
method and send the new state object as an argument:
function increment(ctx) {
ctx.set({ count: ctx.get("count") + 1 });
}
function decrement(ctx) {
ctx.set({ count: ctx.get("count") - 1 });
}
Take a look at minimal example to get acquainted: https://mk0y.github.io/grains.js/examples/minimal.html.
All examples can be found in the repo: https://github.com/mk0y/grains.js/tree/main/examples.
Why Use Grains.js?
✅ Lightweight & Fast
✅ Declarative State Management
✅ Zero Build Step
✅ Reactive Without Virtual DOM
With Grains.js, managing state in HTML is intuitive and powerful, making it a great alternative for small, interactive UIs without the overhead of larger frameworks.
🚀 Try it out and bring reactivity to your HTML effortlessly!