Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: CalDOM: An agnostic, reactive and minimalist JavaScript UI library (caldom.org)
107 points by dumindaxsb 6 months ago | hide | past | favorite | 57 comments

I honestly don’t know where this will lead. Probably all of this is just for nothing. The world has enough UI libraries already. Duh!.

I decided to make my own mini jQuery years ago because I wanted a lightweight library. Also, I wanted to stay close to the native DOM API & vanilla JavaScript. Looking back, it paid really well. Then React & Vue JS happened.

In my opinion, the reactive UI approach bought a huge productivity improvement from the perspective of the developer. Also, it enabled a lot of beginner developers to navigate the programming landscape more easily.

However, this shift also moved people away from the core stuff that’s happening under the hood. As a result, sometimes we have to struggle a lot to find solutions within the library’s limits, which are sometimes hilariously dead simple & performant to implement with native APIs.

CalDOM tries to solve this by being 100% interoperable with the native DOM. I hope this will be helpful for developers with similar requirements.

> I honestly don’t know where this will lead.

The best approach for myself has been implementing the thing I use to some degree as a learning exercise. Not as in "production ready and feature complete" but rather as an exploration of the major mechanisms and basically playing around. It's fun!

Some library like this is going to blow up in popularity eventually. Virtual DOMs are often unnessary abstractions, Svelt introduces it's own whole compilation step, and libs like Vue, Ember, and Angular are just too big.

There is clearly a need for a lightweight (on the order of 3kb seems good) "framework" that embraces everything the modern browser lets you do as natively as possible, basically the new jQuery, or maybe more accurately the new Backbone.js.

What is the audience for this lightweight framework you have in mind? Devs supporting server-rendered sites with minimal JavaScript?

In that scenario I can understand how the build step could introduce complexity, but I'm a bit surprised to see Svelte lumped in with the others simply because it introduces a compiler. If size is a concern, it's hard to beat Svelte emitting framework-less vanilla JavaScript (whether as a complete single-page app, or as piece-meal components you sprinkle throughout a more minimal site).

My desire for such a system is driven by wanting to have a fully interactive development environment that I can work with from inside the browser. Something like the Figwheel/Clojurescript setup without all the moving parts that is accessable directly from the browser console. Svelte fails in this regard since the entire system is not available at runtime.

But Clojurescript is a JS compiler too...?

Regarding the in-browser experience, does Figwheel do something that browser extensions for React/Vue don't do? These tools allow you to inspect component state, replay events, etc. Not exactly sure how much IDE we're talking about here (for example, GitHub Codespaces comes to mind).

I guess I'm just confused at exactly who the audience is that you have in mind. What you're describing here sounds like the opposite of a minimal, native-friendly framework.

Clojurescript is at least available at dev time thanks to figwheel.

Vue and React do bring along the whole runtime and allow introspection, but have abstracted away the browser to a great degree.

The problems really break down like this:

Clojurescript: Doesn't run natively in the browser, requires too much tooling, interactive development during development but doesn't make it into production.

React/Vue: layer of abstraction over native browser APIs, also unacceptably large

Svelte: Not available at runtime

Flippantly, the audience is me, but I'm trying to better put into words why I want this. The idea is to get closer to the experience of developing CL with SLIME/Emacs, where you really are poking around on an active living system. I find that form of development to be the most productive, and it seems like the browser + inspector console is a great potential place for such development with the right set of libs. I want a library that is fully available at run time yet small enough that you can send it into production. And I want to to fully embrace web standards for good or ill rather than try and fix the web via layers of abstraction. Last, I want it to have a very minimal surface area so the whole thing fits in your head, think something like Backbone.js where you could read the whole things annotated code in a day and wrap your head around it.

I appreciate your replies, you've helped me at least try and better refine what I'm thinking of.

No problem, glad I could help - that does clarify where you're coming from. Interestingly, when Brendan Eich was creating JavaScript, he actually intended to make it more like Scheme before his supervisors pushed him to make the syntax more like Java. So I think your thought process is inline with his original intentions.

When you say minimal surface area and "whole thing fits in your head," I can't help but think of the Alpine.js API. Although I'm still mixed on how I feel about Alpine, I can't deny how beautifully simple the API & docs are for it.

I also wonder whether web assembly could play a part in what you're suggesting. It's a part of the web platform, would potentially help with providing robust in-browser tooling... even the S-expressions of human-readable .wat files look rather Lisp-like, albeit too low-level for most frontend work. But I don't know wasm that well, just thinking out loud.

Alpine does look neat, but it feels like its coming at the problem from a different direction than I'm thinking. Alpine looks like it wants to expose you to JS functionality via HTML attributes. My issue with this approach is that every time I've tried it, one eventually hits the limits of what the tool anticipated. Also Alpine looks like it leans on putting literal JS into HTML tags for execution which I don't like since this code is often difficult to debug, lint, reuse, etc.

I prefer the alternative approach where you move as much of the system as you can into JS, since JS is a fully functional language that will adapt to any issue you might run into. Your static HTML would really just be a static skeleton focusing on layout leaving your dynamic content to be dynamically created by JS. Your JS could keep references to those elements in code and then not rely on selectors to find what you need.

With web assembly I'd be really shocked if it was able to provide the same kind of dynamic interactive environment as the Javascript console, but I'm not that well versed in webasm so who knows?

Definitely feel the same way about Alpine. Philosophically I get it, but I agree about how using attributes obfuscates too much. The idea of debugging js in attributes sounds horrible.

Not sure if you've used the multiline console that Firefox has, but I could easily see some repl-driven development with that; I just wish the other browsers had it too.

Petit-vue, from vue's author, addresses this already. No virtual dom, weigth a few kb.

You either

* write stateful UIs (native, jQuery)

* have a Virtual DOM (React, Vue)

* use a template language that is JIT or AOT compiled (Angular, Svelte)

Those are your choices.

I swear React has rotted the brains of a generation of web developers. We've been keeping state out of the DOM with POJsOs before there even were popular frameworks.

If only there was a reactive handlebar

https://ractive.js.org/ ?

(A predecessor to Svelte)


Some good points, especially about framework abstractions sometimes turning certain otherwise trivial things into hilariously overcomplicated piles of "why".

Good luck with your lib.

Thank you! :)

Introducing CalDOM, an agnostic, reactive & minimalist (3kb) JavaScript UI library with direct access to native DOM.

Instead of pulling you into a library-specific magical world, CalDOM let you fully access the DOM directly while keeping the reactivity. A 2-in-1 virtual-DOM & no-virtual-DOM approach if you will.

So you could take full advantage of native APIs & mix it with other libraries to gain superior performance & flexibility in the development process.

CalDOM does not require any dependency or tooling. It does not introduce any new syntax. Just pure JS.

This is the first time I’m publishing something like this. This was a simple jQuery alternative I made myself years ago & kept on improving it slowly. Worked really hard during the last few months to add reactivity and get it to this level.

Please check it out & let me know what you think, the good, bad & your suggestions to improve it.

Also, it's great if you could contribute to the project: https://github.com/dumijay/CalDom

I was prepared to say "meh, whatever another JS lib" but this actually looks interesting!

Nice work from what I see so far.

Thank you very much!

Actually, I was very nervous about "meh, whatever another JS lib" response.

I'm relatively new to HN. This community is awesome!

The aesthetics of a programming language or framework are pretty important IMO, that's one of the reasons Python is my favorit language. This has a lot more punctuation, weird characters (underscore, seriously?), parenthesis and brackets than I ever willing to write or look at. In other words; it's very ugly.

I also don't like underscores much, but this is JS, so shouldn't `window.identifierOfYourChoice = _` alias it without much ado?

I understand.

I picked it mainly for 3 reasons. In my opinion,

1. _ kind of hide itself & give more prominence to the rest of the code (logic) 2. If we pick a long name like CalDOM, it becomes a PITA when it repeats so many times. 3. Not to be conflicted with jQuery by using $

To avoid conflicts, CalDOM provides an official workaround to define the alias before loading: https://caldom.org/docs/#_cal_dom_alias

I understand. Thank you for the feedback.

If you don't like the underscore, there's an official way to alias it: https://caldom.org/docs/#_cal_dom_alias

I actually forgot to mention this in the documentation, your feedback prompted me to do so.

Rest is just the nature of JavaScript my friend. I hear you on Python.

Is your aversion to an underscore more about a variable identified by that or its presence at all?

For the latter Python encourages slug_case_naming_schemes and _ is a valid identifier in Python too. So there's nothing going on here beyond normal Javascript syntax which can be closure heavy -- a main feature of Javascript.

Looks interesting! Kudos on the well documented source, benchmark and website.

Are Caldom instances itself always synced with the DOM? e.g. If I create a Caldom instance for all ‘button’ and add an event handler for ‘click’. Now another piece of JavaScript adds a button to the page, will the event handler also trigger for that button or just the buttons when I first instantiated Caldom?

Thank you. Worked really hard on the benchmark :)

No, it's not synced. When you use CalDOM without its reactive features, it's just a wrapper around the native DOM Element (similar to jQuery).

_("button").elem === document.querySelectorAll("button")[0]

Regarding capturing events of future elements: You can achieve this by setting an event listener to the parent.


_("body").on("click", e => { if( e.target.matches("button") ) //Do something });

That reminds me, few weeks ago, I read that Preact (a 3kb React alternative) could soon become faster than Vanilla JS.

Source: https://twitter.com/_developit/status/1412451442946981890

Preact is awesome and the tooling around it is really refreshing. I'd choose it over react for almost all use cases.

Preact is a very underrated project as is inferno. React casts a big shadow.

Hope this is helpful: the docs at https://caldom.org/docs/ have the table of contents cut off if the window is less than about 1800 px wide. Lots of screens are 1440 or 1280 or even 1024 px wide and won't be able to properly view the documentation. I think it would only take a few simple CSS changes to fix this.

Yeah. Thank you for the valuable feedback. Working on it.

Since I've started using Svelte (HTML-oriented, rather than JS-oriented), every other framework feels like such a mess.

I highly recommend React/Vue folks to check it out, it's literally 2x'd my productivity and completely obliterated the mental RAM i had to keep in order to "think in react"

Oh damn. I've been working on a project using very similar tricks for the passed ~3 years.

I'm assuming state is a proxy and you're using the single threaded nature of JS to make render functions dependent on accessed variables?

Exactly, and state changes are batched behind requestAnimationFrame :)

Also, there's .react(new_state), which is synchronous.

If one prefer not to use Proxies (old browsers, etc), it can be disabled via .react( state, { ..., watched: false } ) and then can call just .react() manually after state changes. Which is also batched(async).

Woah. Congrats. This is pretty much exactly the setup I've been using for a few years now. It is -- without a doubt -- vastly better than any other frameworks approach I've ever used.

Same technique is used for .$ reference holder. Proxies are awesome! :)

Am I the only one to write my own “framework” from scratch every time I start a new project?

These new “super lightweight frameworks” are only 3kb and as fast as vanilla js because they really don’t do much...

They always end up getting in the way though one way or another.

Writing a state and updating the DOM when the state changes really isn’t complicated at all.

People who don’t know how to do it need vanilla js template projects, not frameworks...

lately been using Mithril, small api surface but it's been good. I'm enjoying writing JS frontends, again! :) some things can be tricky but the community is helpful. I'm glad others are making tool-less frameworks. just plug it in the script tag and go to work. so props to the author for making something lightweight and straightforward!!

Thank you :)

Interesting I'd still go for Lit (https://lit.dev/) though if you want something light weight and no/little build.


Your reply encouraged me to experiment a little bit.

Turns out, CalDOM already seamlessly merge with native Web Components. I just didn't see it previously. :(

It can be used to create reactive, stateful & native Web Components. Check out this example: https://caldom.org/#web-components

If you happen to play with it, please let me know your suggestions to improve it.


Yeah, Lit is cool & futuristic. However, it's built for ES2019. It requires some effort to make it compatible with previous browsers: https://lit.dev/docs/tools/requirements/

In my opinion, this is the future. Especially, Native Web Components will take over in this decade. CalDOM's long-term plan is to seamlessly merge with native web components when it's widely supported.

What does "agnostic" really mean here? Or, how is something like React not "agnostic"?

It's 100% interoperable with Native DOM API.

Basically, CalDOM's reactivity system does not care how the Element is created as long as it's a Native DOM Element/Node.

It could be _("+div") or document.createElement("DIV") or even jQuery("<div></div>")

See example: https://caldom.org/#reactive-native-node

Also, a CalDOM instance is just a wrapper around Native DOM Element(s).

_("div").elem === document.querySelectorAll("div")[0]

This interoperability allows for powerful integrations & to update the DOM directly by avoiding expensive virtual-DOM diffing.

In React's world, everything is micro-managed(there're pros & cons), accessing DOM directly can be chaotic & usually not recommended.

Why is "get the nth element from a list" spelled "eq"?

For the note: Sciter ( https://sciter.com ) implements CalDOM features out of the box. But better.

In Sciter DOM and vDOM are equally honored.

This CalDOM's (DOM + vDOM population):

        _("+h1").text("Hello World!")

In Sciter is

      .append(<h1>Hello World!</h1>)
And this reactive CalDOM:

    let app = _().react(
            render: state =>
                _( "+h1", `Hello ${state.name}` ) //This is XSS safe

    _("#output-2", app );

    //Edit below line to update state
    app.state.name = "World Reactively ";
in Sciter is

    class App extends Element {
       name = "unknown";
       render() {
         return <body><h1>Hello { this.name }</h1></body>;

    document.body.patch(<App />);

    document.body.componentUpdate({name:"World Reactively "}); // will invoke render()

> But better.

This blunt dismissal is very rude when you don’t even mention that you are the author of sciter.

Yep I was thinking the same. Quite an idiot way to advertise your own product. I'll leave that link untouched.

Sciter is really great.

My pardon. Yes, I am an author of Sciter.

Not exactly "minimalistic" or "lightweight, though, is it?

"Better" here means that JSX and things like element.append(vDOM/JSX expr/) and Element.patch(vDOM/JSX expr/) are implemented natively - does not need any library at all.

Consider these features as an idea for browser vendors / W3C to extend DOM that we all use.

With these features (JSX & element.patch(vdom)) we don't need whole class of JS frameworks like React, PReact, Mithril. Vanilla JS (ES2020 spec) can be used instead. See: https://github.com/c-smile/sciter-js-sdk/tree/main/docs/md/r...

Did you forget to add that your library has a licensing cost? You don't get access to the source code unless you pay.

Sciter is free if it is used in binary form. Same thing as Google Chrome and MS Edge.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact