August 16th, 2024

VanillaJSX.com

The article highlights using vanilla JSX for creating reusable DOM elements, featuring examples like a click counter and todo list, and discusses the "imlib" library for efficient application development.

Read original articleLink Icon
FrustrationCuriosityAppreciation
VanillaJSX.com

The article discusses the concept of using vanilla JSX to create reusable and interactive DOM elements without relying on a virtual DOM. It presents examples of how to implement simple components like a button that tracks click counts and a todo list that allows users to add and remove items. The button component updates its text content based on the number of clicks, while the todo list manages its state through a class that handles adding and removing list items. Additionally, the article explores how to handle large datasets by filtering input and displaying matched results dynamically. The author mentions the creation of a library called "imlib," which was developed to improve the process of building applications and is used in various projects, including a mini-game maker and the author's own website. The overall theme emphasizes the potential of vanilla JSX for building interactive applications efficiently.

- Vanilla JSX can create reusable and interactive DOM elements.

- Components can maintain their own state without a virtual DOM.

- The article provides examples of a click counter and a todo list.

- It discusses handling large datasets through dynamic filtering.

- The author developed "imlib" to enhance application development.

AI: What people are saying
The comments reflect a diverse range of opinions on the use of JSX for DOM manipulation and its alternatives.
  • Many commenters express concerns about the performance and complexity of using JSX, particularly regarding the need for a compilation step and the overhead of DOM manipulation.
  • Several users advocate for alternatives to JSX, such as libraries like Lit, Vanilla.js, and Web Components, emphasizing their simplicity and efficiency.
  • There is a discussion about the historical context of JSX and its inspirations, with references to older technologies like E4X and XHP.
  • Some commenters highlight the benefits of using a virtual DOM, while others question its necessity and effectiveness in real-world applications.
  • Several users share their own projects and libraries that aim to simplify or improve upon the JSX approach, indicating a vibrant ecosystem of experimentation.
Link Icon 39 comments
By @spankalee - 3 months
Returning actual DOM nodes entirely blunts the big advantage of JSX (and non-JSX libraries like Lit) - which is their immediate mode style API, and UI=f(state) model.

You want to return a description of the DOM, rather than the real DOM, because you want to be able to reevaluate your templates repeatedly with new state, and efficiently update the DOM where that template is rendered to.

All the examples here use imperative DOM APIs to do updates, like with this:

    function TodoInput(attrs: { add: (v: string) => void }) {
      const input = <input /> as HTMLInputElement;
      input.placeholder = 'Add todo item...';
      input.onkeydown = (e) => {
        if (e.key === 'Enter') {
          attrs.add(input.value);
          input.value = '';
        }
      };
      return input;
    }

    class TodoList {
      ul = <ul class='todolist' /> as HTMLUListElement;
      add(v: string) {
        const item = <li>{v}</li> as HTMLLIElement;
        item.onclick = () => item.remove();
        this.ul.append(item);
      }
    }
Avoiding those `input.onkeydown = ...` and `this.ul.append(item)` cases, and instead just iterating over items in your template, is probably the main benefit of a VDOM.

(The problem with VDOMs is that diffing is slow, a problem solved by using templates that separate static from dynamic parts, like Lit - a library I work on).

By @novocantico - 3 months
Thanks for taking some interest in my project. It came from being frustrated with the state of SSGs over the past 10 years. I mostly just make static websites, and I wanted something that was simple and intuitive to me, and JSX seemed like a great fit. But I got very tired of the disproportionately scaled complexity of JSX frameworks like React. Long story short, I made an SSG that just renders JSX as strings. It was natural to extend that to the browser to just render JSX as DOM elements. And in a few cases (mostly layout) it lends well to shared components. Overall I'm happy with what I came up with, although some of it is admittedly a little hacky, and IDE support isn't as good as it could be.

[edit] Oh also, this solution works really well for SEO. That's another problem I didn't find solved well in other JSX frameworks.

By @cribbles - 3 months
These "what ifs" are kinda funny because the origins of JSX can be traced back to Facebook's XHP[1], which took explicit inspiration from E4X[2], an early JS standard that looked and behaved similar to the library described here.

[1] https://engineering.fb.com/2010/02/09/developer-tools/xhp-a-...

[2] https://en.m.wikipedia.org/wiki/ECMAScript_for_XML

By @recursive - 3 months
I also made a UI library based on the idea of jsx template expressions that produce real DOM nodes. It also binds model objects to attributes, eliminating some of the imperative event handler boiler-plate. I think it's a great idea, but of course I would.

https://github.com/tomtheisen/mutraction

It lets you do stuff like this.

    const model = track({ clicks: 0});
    const app = (
        <button onclick={() => ++model.clicks }>
            { model.clicks } clicks
        </button>
    );

    document.body.append(app);
By @merlindru - 3 months
VanJS deserves a mention here! https://vanjs.org/

Another interesting thing is that other JSX libraries like Solid.JS also return DOM nodes, and I love that this idea is gaining traction

The closer we get to the platform we're using, the better. Being removed by layers of abstractions CAN be useful, but in practice, I haven't found a use for abstracting away the platform. (yet.)

Maybe huge projects like Facebook benefit from this tho (which I haven't worked on)

By @sophiebits - 3 months
These examples are cool but I think it’s important to note that none of them show components whose props can change over time, since that ability doesn’t seem to be modeled at all. Clever if you don’t need that but I’m having trouble seeing how it would scale to more complex apps.
By @flowerlad - 3 months
This is very similar to Vanilla TSX: https://github.com/wisercoder/uibuilder

Here’s an app written using Vanilla TSX: https://github.com/wisercoder/eureka/tree/master/webapp/Clie...

By @config_yml - 3 months
Reminds me of Action Script 3 which had XML at the core of the language. It was a fun language to work with, but famously failed to become ES4. Oh well, took us 10+ years to arrive close to that with Typescript and JSX.
By @girvo - 3 months
Does the final example not work in Firefox for anyone else? It worked in Edge, but not Firefox for me

    Uncaught (in promise) TypeError: Map.groupBy(...).entries().map is not a function
By @slmjkdbtl - 3 months
I never understand the appeal of JSX over something like

  h("div", {}, [
    h("p", {}, "this is easy"),
    ...list.map((l) => h("li", {}, l),
  ])
With this you automatically get loops, variable interpolation etc without having to invent a compiler and new syntax. Can someone help me understand?
By @ibash - 3 months
People forget what problem the virtual dom and react is supposed to solve.

No better article than this: https://blog.vjeux.com/2013/javascript/react-performance.htm...

By @hizanberg - 3 months
Anyone else used Hono with SSR JSX? [1]

Was super productive and easy to create a Cloudflare Worker Web App that’s free to host thanks to Cloudflare’s generous 100k daily worker request limit.

Generally don’t believe in serverless for larger Apps, but for small websites that you just want to create, deploy and ignore - it’s great!

https://hono.dev/docs/guides/jsx

By @mg - 3 months
What is the benefit of mixing js and html?

    el = <button>Click me</button> as HTMLButtonElement;
What would be the downside of

    el = html.button('<button>Click me</button>');
?

That way no compilation step would be needed and debugging would be easier as the code executed in the browser is the same code the developer writes.

By @EugeneOZ - 3 months
As often happens with minimalistic approaches, it only looks interesting on very small and very simple examples.

After “How would they handle large data?” it turns into an unreadable mess.

Communication between elements is not covered, global deps, DOM updates scheduling, content projection, and so on - you “just don't need it” in small demo examples, but you do need it in the real apps.

By @drikerf - 3 months
Nice project! I do wonder though if jsx is the best way to represent elements in code?

Clojure datastructures makes this so much more enjoyable. Everything is just basic lists and maps which makes it very flexible and powerful.

[:ul [:li "task 1"] [:li "task 2"]]

It's weird that it's not more common for making web apps.

By @whazor - 3 months
I don't see why the type casting (as HTMLButtonElement) is needed. Because document.createElement("button") returns HTMLButtonElement in TypeScript.
By @ilrwbwrkhv - 3 months
Imba is what anyone interested in this sort of thing should look at. I have no idea why it is not more popular. Maybe because JS devs falls for Faang marketing easily.

https://imba.io/

By @andruc - 3 months
It's very strange that when I land on the page for the very first time, I land halfway down the page and I'm staring at a block of random code.

Not what you'd expect to see.

By @talkingtab - 3 months
A side question. The advantage of JSX I see is the ability to connect, declaratively, components. I find this very helpful in terms of understanding programs I write. I wonder if I use React not because of the virtual dom, but simply because of JSX.

So I would like to explore the ability to use JSX in non-DOM environments. react-three-fiber does this with Threejs, but then it is still React oriented. I found this article about parsing JSX https://blog.bitsrc.io/demystifying-jsx-building-your-own-js.... And I know babel has something that parses JSX.

Does anyone have recommendations for doing this. Threejs to me a good candidate - a non React version, since it is a hierarchical system (scene, meshes, materials etc), but I suspect there are other applications.

I made an attempt to implement a Javascript version of Hickey's transducers - a sort of conveyor belt of functions and that is another instance of a series of processing steps that might be best represented in JSX

By @andrewstuart - 3 months
Just out of interest I wanted to see something a little bit similar in Web Components:

    <html lang="en">
    <body>
      <h1>Web Components Examples</h1>
      <h2>Counter Component</h2>
      <counter-component></counter-component>
      <h2>Clickable Button Component</h2>
      <clickable-button></clickable-button>
      <h2>Toggler Component</h2>
      <toggler-component></toggler-component>
      <script>
        class CounterComponent extends HTMLElement {
          constructor() {
            super();
            this.count = 0;
            this.button = document.createElement('button');
            this.button.textContent = this.count;
            this.button.addEventListener('click', () => {
              this.count++;
              this.button.textContent = this.count;
            });
            this.attachShadow({ mode: 'open' }).appendChild(this.button);
          }
        }
    
        class ClickableButton extends HTMLElement {
          constructor() {
            super();
            this.clicked = false;
            this.button = document.createElement('button');
            this.button.textContent = "Click me!";
            this.button.addEventListener('click', () => {
              this.clicked = !this.clicked;
              this.button.textContent = this.clicked ? "Clicked!" : "Click me!";
            });
            this.attachShadow({ mode: 'open' }).appendChild(this.button);
          }
        }
    
        class TogglerComponent extends HTMLElement {
          constructor() {
            super();
            this.on = false;
            this.button = document.createElement('button');
            this.button.textContent = "OFF";
            this.button.addEventListener('click', () => {
              this.on = !this.on;
              this.button.textContent = this.on ? "ON" : "OFF";
            });
            this.attachShadow({ mode: 'open' }).appendChild(this.button);
          }
        }
        customElements.define('counter-component', CounterComponent);
        customElements.define('clickable-button', ClickableButton);
        customElements.define('toggler-component', TogglerComponent);
      </script>
    </body>
    </html>
By @NohatCoder - 3 months
For anyone who can live without <> syntax I made DOM Maker, no compilation step, no injection vulnerability footguns, just make a bunch of function calls in a tree structure, and you get DOM with the same tree structure, complete with non-string event handlers.

Mostly I just do Vanilla.js, but the vanilla DOM creation functions turn really verbose, I got tired of that and created this to cut back on code size and increase readability.

There are other libraries that do something similar, but in my own very biased opinion this is one of the better.

https://github.com/NoHatCoder/DOM_Maker

By @cies - 3 months
I frown at JSX. Just a layer of abstraction that is so "leaky" that you have to know what actually goes on in the layers below or you are fucked.

It looks simpler at first glance/ to a untrained eye; but it's just adding complexity without really solving any problems.

I like approaches like Kotlinx.html, scalatags, Elm's HTML package or HtmlFlow. They are also abstractions, but they add typesafety that html-as-a-string does not offer. On top of that you get breakpoints, code completion, and you can keep working in one language.

By @miika - 3 months
I used to explore similar stuff and prototyped something I call “Vanilla Components” but then in the end I fell in love with Web Components and quit React (and all other frameworks).
By @spullara - 3 months
I was bummed when they removed E4X from the browser implementations.
By @arjvik - 3 months
What benefit does the virtual DOM add?
By @xwall - 3 months
No matter how complex your app is but still React will not break, performance on web is not a big issue as benchmarks say, even a junior developer can achieve 90%+ lighthouse score, but any senior developer may fail to ship it successfully.

ultimately go to react.dev because: "Maturing is realizing React is best"

By @dqh - 3 months
Those interested in this space may find my fairly unknown project interesting: https://nakedjsx.org/

It started as a static site generator but added a bunch of support for client JavaScript too.

By @NaN1352 - 3 months
I’m having fun using vanilla js with lit-html. Using string templates instead of jsx. VSCode extensions for lit make it almost identical to editing vue templates with type checking etc
By @waynenilsen - 3 months
This plays very nicely with the locality of behavior model of htmx
By @n3storm - 3 months
For me is like old PHP where HTML and controlling and data access was all around. We use to call it spaghetti code.
By @cyanydeez - 3 months
I just don't understand how people can configure their brains to parse html inside JavaScript
By @emadda - 3 months
One of the reasons for JSX originally was to reduce usage of the DOM APIs, as they are slower than direct JS object manipulation. The JSX diff of prev/next allows you to minimize DOM API calls.

I would guess there is more overhead in creating a dom element than a JS object (which JSX elements compile to).

By @nf17 - 3 months
Great job, is there something similar but for SwiftUI?
By @nashashmi - 3 months
I wonder what The examples would look like in ECMAscript 5.
By @NaN1352 - 3 months
How does this stack up aginst using lit-html?
By @andruc - 3 months
Any comparisons on performance?
By @frabjoused - 3 months
It’s already solved. It works well. Just walk away.
By @jwtorres - 3 months
I genuinely don't understand why anyone would be interested in using frameworks on top of JS. None of them can do anything that pure JS can't do (+libraries), they just make it less readable and less intuitive compared to the original C-like syntax of JS. JS libraries make sense, of course, but why keep messing with the syntax?