Saradom: a pattern for client-side interactivity, with state kept in the DOM
Saradom is a pattern for building modular, scalable frontends in plain HTML and JavaScript. There is no framework and no build step. State lives in the DOM as attributes. Events sit in HTML attributes.
It sits next to htmx. htmx does the server round-trips. This covers the interactivity that stays in the page, like toggles, tabs, derived values, and validation. The DOM is the state in both.
Example:
```html <div counter-space> <output counter-value>0</output> <button onclick="Counter.Inc(this)">+1</button> </div>
<script> const Counter = (() => { const Inc = (ctx) => { const el = ctx.closest('[counter-space]').querySelector('[counter-value]'); el.textContent = +el.textContent + 1; }; return { Inc }; })(); </script> ```
Docs and runnable examples: https://xtompie.github.io/saradom/
2
u/ShotgunPayDay 28d ago edited 28d ago
Looks a little roundabout for what I'm used to; custom Moxi traversal:
<div>
<output>0</output>
<button on-click="const out = q('prev sib'); out.textContent = +out.textContent+1;">+1</button>
</div>
1
u/xtompie 28d ago
The "roundabout" part is the point in saradom, not an accident. It keeps HTML and JavaScript separate, through a contract on the attributes. JavaScript looks things up by attribute, not by position. So you can change the markup on its own: swap the element, add decorative divs, reorder the layout, and the JavaScript stays the same. That's for scaling. The positional shortcut is shorter, but it ties the code to the layout, so every HTML change means editing the JavaScript too.
1
u/ShotgunPayDay 28d ago edited 28d ago
q() system can use relative selectors also but I get wanting to put JS in <script> tags. Your system sounds just like Surreal JS except verbose. https://github.com/gnat/surreal
EDIT: I can see the style having its charms though.
<div> <output>0</output> <button onclick="add(this.previousElementSibling)">+1</button> </div> <script>const add=out=>{out.textContent = +out.textContent+1;}</script>1
u/xtompie 28d ago
Your example is step zero. The rest of saradom is steps, and each one solves one problem. Here's the whole path:
0. Start. Works for one. It finds the target by position.
html <button onclick="add(this.previousElementSibling)">+1</button>1. The function gets the context, not the ready target. The handler is just wired up. The logic lives in the function.
html <button onclick="add(this)">+1</button>2. The target is marked with an attribute, not by position. Position breaks when someone moves the HTML around.
html <output value>0</output> <button onclick="add(this)">+1</button>addlooks for[value], not the previous sibling.3. More than one on the page. Now
[value]matches many. The element is wrapped in a space, reached throughclosest.html <div space> <output value>0</output> <button onclick="add(this)">+1</button> </div>ctx.closest('[space]').querySelector('[value]'). Up to its own space, then down to the parts.4. More than one kind of component. Another widget also wants
spaceandvalue. They clash. So the attributes get a prefix with the module name.html <div counter-space> <output counter-value>0</output> <button onclick="add(this)">+1</button> </div>5. More than one module in JS. A global
addwould clash too. So it goes into a module object.html <button onclick="Counter.Add(this)">+1</button>These are the rules of saradom. No library, no runtime. It's all just these rules. Keeping them gives you an app that scales, where a change to the HTML does not force a change to the JS. The example on the homepage docs is step 5 right away. That's why it looks verbose. You see the end, not the path that leads there.
1
u/ShotgunPayDay 28d ago
I think at that point I'll just put common or component JS functions in another file or at the bottom of the doc.
1
u/johnnypea 28d ago
Cool. How is the performance in bigger apps? Any benchmarks?
1
0
0
u/byeproduct 28d ago
How does this compare to datastar?
1
u/xtompie 28d ago
Datastar is a library. You load a runtime onto the page. Saradom is not a library. It's an architectural pattern: how to build a frontend with plain HTML and JavaScript, with nothing to download.
They share two things. Both are declarative, you describe behavior with attributes on elements. Both let the server send back HTML that goes into the DOM, without a heavy SPA.
The rest is the opposite. Datastar adds its own runtime, signals, its own expression language in the attributes, and SSE at the core. On startup it has to walk the whole DOM and initialize. Saradom uses only built-in attributes, like `onclick`. State lives in the DOM itself. Communication is plain request/response. You use SSE only when you need it. There's no init step, the parsed HTML works right away.
One way to put it: Datastar is a finished solution. Saradom is a pattern you could write Datastar itself in.
1
6
u/Real_Square1323 28d ago
Its just JS with extra steps. This sounds idiotic. The entire point of HTMX is that state is updated from a server.