Psatina: a new tiny JS framework

While I was building FemtoCRM, I needed a dynamic form for entering sale line items. I could build some basic JS to add and remove rows from a table, but each row’s inputs needed to have the row index in its name (i.e. line_items[2].quantity) which seemed like a pain to manage[1].

I reached for one of those “reactive” frameworks where you define a template and it updates itself in response to data changes. The obvious choice was Alpine.js, so that I could keep the sale form in the HTML template. I don’t like having separate JS files for extremely page-specific stuff.

GitHub screenshot: alpine (public). A user you’ve blocked has previously contributed to this repository. claude.

Great, man. Love that for you.

Well, it’s not just that they slopped my blorbo. I’d been trying to build a JS framework for years. But so far, my efforts consisted of building a collection of tiny libraries and hoping a framework would arise out of that somehow.

Well, it didn’t, and it turns out separate tiny libraries get bigger when you put them together. Over the last week or two, built Psatina, a framework inspired by Vue and Alpine in 1.6 KiB (.min.br).

<template p:data="{ count: 1 }">
  <output>[| count |]</output>
  <button type="button" p:on:click="update(() => count++)">Increase</button>
</template>

Psatina sacrifices a lot to get its small size, mostly in performance – I haven’t tried building a DBMonster with it. I consider it the 20% of Alpine I need for 80% of usecases[2]. I’m thinking about reviving my htmx clone whet to pair with it.


  1. OK, it probably wouldn’t be that hard. But as mentioned, I like my JS components to be general-purpose. For this kind of use case, the generally-applicable tool is a reactive framework. ↩︎

  2. Not actual numbers. ↩︎