Hacker News new | past | comments | ask | show | jobs | submit login
What if we'd had better HTML-in-JS syntax all along? (leontrolski.github.io)
150 points by zdw on May 11, 2020 | hide | past | favorite | 164 comments



> I have a theory that a grave mistake was made in 1995 - the decision not to have a neat, succinct and declarative way of representing html elements in javascript.

It may be interesting to recall that initially the only way to output HTML was by `document.write()` using strings (which was pretty declarative).

The genuine way of generating HTML in JS were various methods of `String.prototype` for generating HTML formatted output, as `anchor()`, `big()`, `blink()`, `bold()`, `fixed()` (providing "<TT>…</TT>"), `italics()`, `link()`, `small()`, `strike()`, `sub()`, `sup()`. However, there was no provision to set an ID or any other attributes or className, since these things (and CSS) hadn't been introduced yet, with the notable exception of the "name" attribute for anchor tags, the value of which was to be supplied as an argument to the `string.anchor()` method. This was pretty much sufficient to generate any of the HTML required then.

The first occasion for a more complex approach was the introduction of the `Link` and `Image` objects, which allowed for the first time not only a representation of a DOM object, but also means to manipulate their attributes on the fly (e.g., changing image sources), but this came only with Netscape Navigator 3.0 / JavaScript1.1.

Also, keep in mind that the JS object notation (object and array literals) was only introduced in the ECMA standard, which came another browser iteration later. Initially, in JavaScript1.0 (AKA LiveScript), there hadn't been even Array or Object constructors in the core language (these came, again, with JavaScript1.1), but only functions. (Meaning, you had to construct your own arrays from generic functions). Hence, something like a declarative HTML-in-JS syntax would have been totally out of place.


There was also the the idea that JavaScript was just one way of scripting the page. VisualBasic Script (VBScript) had momentum in IE releases. The general idea was that the user-agent was going to be able to parse multiple scripting languages, the list of which would probably grow as time went on. Think native TypeScript parsing in a browser today!


There were even things like ViolaWWW [0][1], using a HyperCard-like approach, which exposed all its objects (even a canvas for drawing) and methods in its own scripting language. This was probably the nearest thing to the Web, we know today, but also an absolute security nightmare.

[0] https://en.wikipedia.org/wiki/ViolaWWW [1] http://viola.org

Edit: The basic building blocks of ViolaWWW were horizontal and vertical layout panes, which behaved much like flex elements and allowed the implementation of all the common HTML tags. These were accessible to viola-scripts and could also be generated by a script. Moreover, ViolaWWW also featured stylesheets (in a maybe more declarative form than CSS).

Styles were also much like this, with multiple concurring standards. While MS IE featured CSS, Netscape used JavaScript styles. (However, Netscape soon adopted CSS syntax, but this remained a mere bridge to the original JS styles for all of the NS4.x life cycle.)


Tcl added sandboxed subinterpreters in a bid to become a safe web scripting language. The plan didn't work out but it is a killer feature for untrusted input.


>Think native TypeScript parsing in a browser today!

If only...

Or better yet, a bytecode format that is easy to target for scripting languages like typescript, clojurescript, scalajs, coffeescript, dart, and even plain JavaScript. Webasm is too low level (at least currently) since it doesn't have a GC, direct DOM access, etc. Most js engines have an intermediate bytecode representation anyway, it would be cool if you could target that instead of textual js.


ActiveState had browser plugins for Perl, Python and Tcl. I think they were IE only via COM extensions.


Netscape had a plugin API and there was a Tcl plugin for it. As I recall the Netscape API was the de facto standard for as long as plugins were a thing, so the Netscape plugin was usable in conforming browsers.


Well, with a bit of luck you just need to ship a TypeScript compiler/AOT/JIT shipped as WebAssembly module. :)

The best way to take advantage of WebAssembly, since it is here anyway, is to abuse it to recover all plugins that were taken away.


> It may be interesting to recall that initially the only way to output HTML was by `document.write()` using strings (which was pretty declarative).

I think people also forget how slow a lot of JS was really until V8. I remember having server code generate JS arrays (creating them from an xhr request was too slow), that in turn would document.write (manipulating the DOM was also super slow) data on the client to make the web page 'interactive'. It was messy.


It wasn't just JS, you could actually watch JPEG images becoming decoded, esp. on a computer which wasn't exactly new. Layout of complex markup could take seconds, reflowing and repainting was out of question. JS as an interpreteded language was accordingly much slower than native code. There was no way to do fast, declarative HTML in JS – and not much of a use case for this. (For much the same reasons, there was no way to have optimizing client-side JS engines, even if JS hadn't been just in its infancy.)


Ah, the render one scanline at a time effect in analog modems.

I even used to disable images and just selectively download them.


> creating them from an xhr request was too slow

You had XHR? Luxury! We had to embed a 1x1 px Java applet to communicate with the server without reloading the page! ;)


Haha...at the time I was writing internal business applications where everyone could be forced to use IE. Another thing people forget is that at one time IE was the best browser. It was because that IE had such a lead it stagnated and we ended up in the IE6 situation.


So, if initially there were no Array nor Object constructors (there were arrays and objects, but only prepopulated ones, representing anchors, forms, etc, found in the document), how were arrays done in a script?

  function MyArray() {
     this.length = 0;
  }

  function arrayPush( value ) {
     return this[this.length++] = value;
  }

  function arrayPop() {
     return this[--this.length];
  }

  MyArray.prototype.push = arrayPush;
  MyArray.prototype.pop = arrayPop;

  var a = new MyArray();
  a.push("frist");
  // no console available, debug using alert()
  alert( a[0] );     // "frist"
  alert( a.length ); // 1
  alert( a.pop() );  // "frist"
  alert( a.length ); // 0


I have been using JS since the mid 90s, but I don't recall needing arrays or objects back then. Frankly we weren't trying to build applications and any real programming work was done on the back end (remember that xmlHttpRequest wouldn't exist for years to come, so any changes to the page were made by going to a new page which would require a round trip to the server, so the server could do anything it needed to do to the page before returning it). The only things I can recall using JS for back in the early days was displaying the date and time at the bottom of the page (why we felt like that was useful is beyond me).


There were a few interactive scripts, usually interacting with a form as an UI. The first JS book, I knew, was the "Official Netscape JavaScript Book" (1996), which was based on Netscape 3 beta. This one featured a pretty complex area code application as a demonstration object and things like order forms. I started pretty much with the introduction of NS3, when NS2 and JavaScript1.0 were still the common platform.

Fun fact, for a year or so, you'd frequently include a script twice, once in a simpler form for NS2 and similar, and once targeting Netscape 3 (and, later, IE3) using a `<script language="javascript1.1">` tag, which was ignored by the earlier browsers, implementing a more complex version of the same functions. (This scheme was used again, when DHTML became a thing, this time using the `language="javascript1.2"` attribute. However, this switch came with a few caveats, since it also activated some rather odd behavior, like negative zero as a numeric value, which could break a few things.)


what a trip, I forgot about displaying the current time and date haha. The other major usage I had for JS back in the day was to focus the cursor on the login box on page load.


The other major uses of JavaScript were hover-over-button effects, and scrolling text in the status bar


Oh my. I'd forgotten about scrolling text. Why did we do that? LOL


What a magical time... I remember being wowed by having a string of text follow my mouse around.


There was no `prototype` and `constructor` properties

    o = new Object
    o.foo = 'bar'
    a = new Array
    a[0] = 'baz'
But functions were constructors

    function hello() { return this.name }
    function Person(name) {
      this.name = name
      this.hello = hello
    }
    new Person('James')
Array push

    var length = 0
    a[length++] = 'foo'
    a[length++] = 'bar'
Actually it was not bad for scripting language, no WAT:

    new Object + new Array
    //null is not a number
No `typeof` (so no `typeof null`), better `parseInt`

    parseInt("foo")
    //0
Much better start than ECMAScript 1


> There was no `prototype` and `constructor` properties

You are correct. The prototype property was yet another JavaSript1.1 (NS3) feature. (Totally forgot about that.) So, ignore '.prototype' in my example. But you could assign properties and methods to objects. Therefor it was more like,

  var a = new MyArray();
  a.pop = arrayPop();
  a.push = arrayPush();

> No `typeof` (so no `typeof null`), better `parseInt`

Fun fact: also no `isNAN()`. This was, once again, introduced with JS1.1/NS3 and still nonfunctional in IE3 – yes, IE3 had a few of those nonfunctional implementations.

(`isNAN()` was actually available in the Unix implementation of Netscape 2, but this was of lesser concern for the public Web.)

On the positive side, the access to forms and the various form elements was pretty sound and mature, right from the beginning, since this was what JS was pretty much all about.


Sorry, NN2 does not agree, it overwrites `length`:

  function MyArray() {
     this.length = 0;
  }
  var a = new MyArray();
  alert(a[0]) // 0
  ...

  alert( a[0] );     // "frist"
  alert( a.length ); // "frist"
  alert( a.pop() );  // JavaScript Error: length is not a numeric literal.
  alert( a.length );
How clever - https://www.javaworld.com/article/2077150/using-javascript-s... - all you have to do is count from 1


You are correct, once again, all properties were available both by property name (if used in an associative context) and by numeric index. Since we assigned 'length' already in the constructor, we would have to accommodate for this, i.e., start counting at 1.

Turns out, my recollections are a bit on the rosy side… :-)

Edit: This should work:

  function MyArray() {
     this.length = 0;
  }
  function arrayPop() {
     return this[this.length--];
  }
  function arrayPush( value ) {
     return this[++this.length] = value;
  }

  var a = new MyArray();
  a.pop = arrayPop;
  a.push = arrayPush;
  a.push('a');
  a.push('b');
  alert( a[1] ); // 'a'
  for (var i = 1; i <= a.length; i++) alert( a[i] );
at which point it is much simpler to do:

  function MyArray() {};

  var a = new MyArray(), aLength = 0;
  a[aLength++] = 'a';
  a[aLength++] = 'b';
  for (var i = 0; i < aLength; i++) alert( a[i] );

  var b = new MyArray(), bLength = 0;
  // etc
which is also, what was actually used.


Strings are so tempting because they are there and everyone knows how to use them.

But they are the wrong abstraction for building DOM nodes. They're error prone (no guarantees of correctness) , encoding woes) and are write only (how do you modify a node that is encoded in a string). And what do expressions like html.substr(0, 7) even mean?

First class HTML composition in JS is pretty dang important.


HTML should be expressed in the data literals of your programming language, this is easier if you have a literal data type for names like Erlang and Clojure

Once you have that, you have a always "parsed" HTML that you can serialize, send over the wire to other languages, rewrite with ease and change the render target if need be

Some other commenters have shown what that looks like in practice


The "object" syntax reminds me a lot of Clojure/script's Hiccup (https://github.com/weavejester/hiccup) style, which has become a de-facto standard across many popular libraries. In hiccup, this example:

    {
        tag: "button",
        attributes: {
            "id": "baz",
            "class": "foo bar",
            "data": "1",
            "onclick": f,
        },
        children: [
            "Hello",
            {
                tag: "em",
                attributes: {},
                children: ["there"],
            }
        ]
    }
Would be represented as:

    [:button#baz.foo.bar {:data 1 :on-click f} "Hello" [:em "there"]]


Thanks for mentioning this. I was about to say that those of us who write ClojureScript do not have the original problem: my functions return vectors with data, which then get turned into HTML, DOM objects, or React classes, depending on the specific use case.

In other words, there is only one language and one syntax to deal with.


That looks identical to WC3 XML Schema language using JSON syntax instead of XML syntax.


I think you've missed that the hiccup example is the code on the final line.


I think my favorite thing about JSX specifically - is that the {} breakouts used in it, get all the same treatment from the JS/TS compiler as your Javascript/Typescript does. And all without changing HTML into a JSON or Yaml representation. It just works in VSCode. The number of years of HTML being an relative of the SGML/XML family (pedants calm here, you know what I mean) shouldn't be thrown away just because it's not immediately available in JS.

I think one thing I would love to see from JSX is for it to start growing outside of the React world. Vue seems to be trying. Until React came along, we really had no compile time checking on templating languages at all. I think the reason for that, is, in part, because the templating aspect was always thought of as "dirty" that you shouldn't mix JS and the view parts. I think React debunked that notion. I've never been as productive in creating UIs as I have when I'm working in React. And a lot of that is because I call my backend, I get a typed object back, I tell the UI to use <div>{response.medication.firstName}</div> and if we ever change the structure of medication? I get full help from the compiler that that view will no longer work... If you haven't used React you might not get the full power of that.

Even if I am a React fan, it doesn't mean I don't think other frameworks won't ever take over, but I think at this point, the one that may eventually eclipse React is probably going to have native JSX support.


Yeah, agreed. React and JSX really shines with a good component library, and the key word with react is composable. I don't know that, by itself, better syntax for HTML-in-JS would advance the state of the art. Instead of having divs and spans everywhere, they're an implementation detail of components.

I can change

    <leftPanel>
        <userInfo>
    </leftPanel>
    <rightPanel>
        <medicationsPanel>
    </rightPanel>
to

    <topBar>
        <userInfo>
    </topBar>
    <leftPanel>
        <medicationsPanel>
    </leftPanel>
Without having to know what html+css tricks topBar is doing under the hood.

Inside of medicationsPanel, there's <medicationsList> which is the `ul`.

    <ul>
        {medications.map(m => {
            <medicationListItem item=m />
        })}
    </ul>
medicationListItem has the `<li>`, with the styling living somewhere inside. Templates, especially in separate files, don't really manage to be composable with the same ease. Leaving the divs and spans and CSS to the lowest levels of the component library does wonders for making the code easier to reason about, and maintain. React code from a few years ago still has some warts, but it's still way less painful to try and pick up than code that was written with traditional templating. (Specifically, the templated project was using `.erb` files.)

React threw out MVC and templates (though some say it's just the V instead), and is worth learning just to feel like it's possible to implement UIs cleanly.


Webcomponents should help with this. Although the current API is not as pleasant to use as react.


They can't and they won't. Because they rely on DOM APIs to do anything useful. Which brings us back to the article.


What does that have to do with having composable components?


Everything.

The only way the vanilla webcomponents are "composable" is through tons of boilerplate code using DOM APIs. You can't even re-create the example with list elements without tearing your hair out when using webcomponents.

It's so bad that any examples showing "composability" immediately give up and use .innerHtml everywhere, and even then it's pretty bad.

It's so bad, in fact, that people do anything to avoid writing vanilla and use lit-html (yay, programming with strings), Stencil, or even Preact (AMP switched to Preact to author components).


What I would love to see is something like jsx supported directly by the browser. Although, I'm not sure what that would do in non-browser EcmaScript environments. Perhaps something like lit-html's html string tag is more likely to be standardized.


I was going to bring up Polymer's lit-element / html`` syntax but decided it was a dead horse - but in any case, hopefully that isn't the way things go. Even though the breakouts ${} are JS and the compiler can help with those, it doesn't do much for repetition. I really think that's one area that angularjs -> angular X really struggled was templates that repeat things... React pulled that off so f...ing fabulously. It's just a map that emits more elements!


That's exactly what lit-html does:

    html`
      <ul>
      ${items.map((i) => html`<li>${i}</li>`)}
      </ul>
    `
...so I don't understand the critique.


Stencil uses JSX.


An early alternative would've been to use an integrated language for both HTML and JS features, like Curl, published in 1997:

https://en.wikipedia.org/wiki/Curl_(programming_language)

https://dl.acm.org/doi/10.1504/IJWET.2003.003259

https://groups.csail.mit.edu/cag/curl/wwwpaper.html

(Disclosure: I worked at the Curl commercial spinoff.)

Or, many Lisp people just used s-expression data for HTML, and Lisp for everything else. Here's a typical way I did, in 2000, in Scheme:

https://www.neilvandyke.org/racket/html-writing/

And a less-common later take on it, which used syntax extension rather than data:

https://www.neilvandyke.org/racket/html-template/

I actually pitched some Web ideas to Tim Berners-Lee around 2000, including Scheme for Web programming. But shortly after that, he promoted using Python for some Web stuff, because, IIRC, Python was inclusive, making Web programming accessible to more people. Which was understandable, and one of the ways many techies thought about the Internet, before there were career tracks, when the Internet was something we knew about and wanted to bring to the world. (In hindsight, I wish I'd then tried to write a very inclusive practical intro book/tutorial for Scheme at that early point, but I was preoccupied with other things.)


The modern equivalent is Hiccup and Clojure. https://github.com/weavejester/hiccup/wiki/Syntax

Clojure has literal lists using parens and vectors using square brackets. By using both you can mix code and markup in a readable way. It's great!


Don't forget E4X: https://developer.mozilla.org/en-US/docs/Archive/Web/E4X_tut...

It never really caught on.


Yes, I am still sad about this. A simplified XML (without entities, PIs and CData sections), XHTML and E4X would have been an awesome platform. Almost as simple as JSON, and with a single format for both data and markup.


That MDN article is fairly limited - a whole javascript syntax for querying documents came with it: https://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e...

In the end we jumped from ES3 to ES5, skipping all of E4X. I wonder if we're better off.


We use it in healthcare, at least in NextGen Connect, formerly Mirth Connect[0]. It uses Rhino[1] as its scripting engine which still supports E4X.

[0] https://en.wikipedia.org/wiki/NextGen_Connect

[1] https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rh...


That is really cool. I had no idea anyone was still using it.


I mean, it kind of caught on. It's syntactically very close (if not identical) to JSX. It just caught on in a different form/technology than what was built into Gecko. I think if it had been introduced later, with the kinds of performance seen in VDOM implementations, it may have had a greater chance of becoming a web standard.


Ultimately what is in the way of it being implemented now or in the near future? Is there anything?

I don't see why it couldn't just live beside the current Element API.


The standards bodies have historically tended to adopt lower level APIs over higher level abstractions. I think the likelihood of JSX or E4X or whatever, as such, making it through the standards process is fairly low.


Wow. I'd never heard of this.

And now instead we have virtually the same thing via JSX except we now require a compilation stage to achieve essentially the same thing...


I'm sure it was one of the inspirations for JSX -- https://facebook.github.io/jsx/#prior-art


The creators of JSX (Facebook employees obviously) once said in a talk that their biggest inspiration for JSX was server-side PHP code which supports being interspersed with HTML.


> PHP code which supports being interspersed with HTML

You're one of a large number of people who say this, but it is false. PHP intersperses a programming language with static strings. Those static strings frequently adhere to HTML syntax, but that's aside from PHP.

What is HTML? It's not random strings; it's a syntax. JSX is much closer to interspersing HTML with a Turing-complete programming language than PHP ever was, because frequently the mistakes that make JSX not compile are the same mistakes that make HTML invalid.

Admittedly I haven't used PHP since 2012, but at least back then you could make all the HTML mistakes you wanted, and PHP wouldn't bat an eyelash.

EDIT: Here's someone else's comment making the same point in different words. If my comment doesn't make sense to you try this one: https://news.ycombinator.com/item?id=23144268


You're technically correct, but I don't think the distinction adds anything to the conversation. I don't know if PHP was the inspiration for JSX, but if the strings they were using in PHP was HTML, then it could have been.

EDIT: Sounds like JSX was inspired by XHP: https://www.facebook.com/notes/facebook-engineering/xhp-a-ne...


A lot of the objections people have to "mixing code and HTML" stem from experience with PHP and similar technologies. The distinction is important, because JSX is less objectionable than PHP.


Besides, the parent never said that PHP was restricted to being mixed with HTML, they just said that it was possible. The contradiction of this is technically incorrect.


Link?

You might be misremembering Pete Hunt's talk about React's design decisions: https://www.youtube.com/watch?v=x7cQ3mrcKaY where he makes the case against the "separation of concerns" cargo cult.


Sorry, I don't remember the link. It may have been this talk from 2013, but I haven't rewatched it: https://www.youtube.com/watch?v=XxVg_s8xAms

However, if you check out the History section [0] on Wikipedia you will see this confirmed:

> React was created by Jordan Walke, a software engineer at Facebook, who released an early prototype of React called "FaxJS". He was influenced by XHP, an HTML component library for PHP.

[0]: https://en.wikipedia.org/wiki/React_(web_framework)#History


Yes, XHP, also by Facebook


JSX was a direct port of XHP to Javascript.


The problem with E4X is that it's only data; you can't define a new tag that reduces to new primitives. This kind of composability is why XHP (in PHP) and JSX are so useful.


Javascript already has the ability to define new abstractions. They're called functions.

Imagine you want a new "tag" for defining a Widget. Make yourself a Widget function which takes some arguments, maybe the name of the widget, the mass, and the price. Those arguments can themselves be HTML, created either using E4X or any other means you like. This lets you compose things together. For example, perhaps the price could just be a number today, but tomorrow you want to let the user do currency conversions and so you make it a more complicated AJAX thing that lets the user view the price in any currency they want. Today you would have Widget("Plumbus", kg(1.1), 49.99), but tomorrow you could change it to Widget("Plumbus", kg(1.1), Currency(USD, 49.99)). No new inventions required.


Sure, but the why are we talking about special syntax in the first place? In any non-trivial projects you're rarely going to be working with primitive tags, it's always higher level components.


Because all higher-level components must be created out of primitive html tags with a sprinkling of attributes, and it's nice to have a convenient way to create those. This is the same reason why modern languages include some kind of object-literal syntax rather than relying purely on constructor functions. Even C has a comprehensive syntax for initializing objects now. E4X was just that for HTML and XML.


Something close to this is possible already in JS, I'm working on a library for generating HTML in node, heavily inspired by Haskell's blaze and lucid. Example code:

  div(
      { class: "table-responsive" },
      table(
        { class: ["table table-sm", opts.onRowSelect && "table-hover"] },
        thead(tr(hdrs.map(hdr => headerCell(hdr)))),
        tbody(
          vs.map(v =>
            tr(
              mkClickHandler(opts, v),
              hdrs.map(hdr =>
                td(typeof hdr.key === "string" ? text(v[hdr.key]) : hdr.key(v))
              )
            )
          )
        )
      )

The first argument to a tag is optionally an object with the attributes, any subsequent arguments are children of the tag, or an array with the children.

EDIT:

the library as a gist: https://gist.github.com/glutamate/69d38fb1d2024cb829edfff57d...


This actually already exists as a library. This type of syntax is called Hyperscript[1], and it's existed (at least) since 2012.

[1]: https://github.com/hyperhype/hyperscript (Although this library does not look maintained anymore)


Cool! I was looking for something like this but couldn't find it. Oh well, building my own kept me sane during lockdown.

I think combinator libraries like this and one I'm building are definitely better than templating languages, although JSX can also work really well, in particular because it retains the HTML syntax making it easy to copy from the browser into code.


You can also take a look at mithril.js implementation of hyperscript [0]

  [0] https://github.com/MithrilJS/mithril.js/blob/next/render/hyperscript.js


was about to mention Mithril.

solid framework, but not great for large applications.


What issues have you encountered that make it not great for large apps?


it has been a few years, so maybe these issues have been addressed at some point since I used it last, but:

1) there were multiple issues with deeply nested object models not being reactive within the UI code that cause me to explicitly call m.refresh (can't remember the exact api, as it has been a while, but the function that was called forced a virtual dom refresh, which was _not_ good for performance). I ended up writing a debounce function that would make sure the m.refresh function only got called once per paint at the most, which helped, but it was just a band-aid over the underlying problem, which was that the framework was not detecting reactive property changes within deeply nested models. At the time I was using it, there was no other remedy according to issues that had been brought up on stack overflow.

2) this is probably personal opinion, but the hyperscript model for structuring html, while it looks good on paper, lends to a really tedious process of writing html-generating javascript.

I guess I didn't need a numbered list. Those were my main two gripes.


For (1), m.redraw() is async; I don't think you have to debounce anymore. The autoredraw system may be more sophisticated than when you used it, too. https://mithril.js.org/autoredraw.html

For (2), I've been using JSX with Mithril the whole time. My team and I didn't like deeply nested hyperscript either. (At my employment we're in the process of moving away from Mithril, but I'm still using Mithril 2 in a side project)


Curious why you claim that. It can be used the same way as React is used, and React is largely touted as something that is fitting for large apps.


Yup, it's almost exactly the same syntax if you use Hyperaxe (built on top of HyperScript): https://github.com/ungoldman/hyperaxe/


hyperscript itself is basically Elm without the Elm language


The Re:DOM library might be of interest — it's very similar to your syntax above and it also comes with a robust toolkit for handling updates without the overhead of a virtual DOM:

https://redom.js.org/#elements


Neat! I made this exact same thing, but a bit more robust a while ago. It's amazing to see how similar it is. The implication is that it's likely logical.


I definitely had a positive experience using in on a moderate sized project last year — the biggest thing I liked was how simple it was. Everything is standard JS & browser APIs so there was zero overhead when debugging.


I went with this syntax as well for a project [1], being just a simple wrapper on top off createElement, with functions as children/attributes being used as one-way bindings.

1: https://github.com/bwindels/brawl-chat/blob/master/src/ui/we...

Works very well, and don't need to transpile.


How is this different from just using a hyperscript library directly and bypassing JSX-like transpilation?


Solenya does pretty much exactly what you've described: https://github.com/solenya-group/solenya

Interestingly, in a very early version classes were allowed to be expressed as arrays of strings just like you had, but in the vast majority of cases a space delimited string worked fine, so this feature was dropped for simplicity/uniformity.


I added the option to have classes as an array of strings to facilitate conditional classes. (I then filter out falsy values so I can use a simple

   condition && "conditional-class"
At the end of the class list.)


Slightly more verbose (buying code size): https://github.com/stefanhaustein/notemplate


I really like specifying event handlers with functions, I've got to see if I can get that to work with server side generated HTML.


I think flutter puts a nail in the coffin with its semi-declarative syntax.

While you're technically programming using an imperative language, they've somehow managed to make the syntax close enough to a declarative one that it isn't just a soup of bare object surgery (like tkinter or java swing).

They also, really went the extra mile to NOT have to do tree diffing[1], by making Widgets immutable, while still having a "detached" State associated with them.

And this is eerily close to the JSON-is-HTML syntax the author is proposing. A replication of flutter's strategy in pure JS is defininitely worth exploring.

[1] https://flutter.dev/docs/resources/inside-flutter#linear-rec...


This reminds me of a very cool property of the Lua language that allows for very neat "syntax extensions", and reminds of functional languages too:

If you have two expressions adjacent to eachother, it evaluates to calling the left-hand side with the right-hand side as a parameter.

At its simplest:

  function foo(text)
    print("Foo:", text)
  end

  foo "bar"
But you could implement a JSX-lite in it:

  function Div(props)
    return function(children)
      return ViewLibrary.createElement("div", props or {}, children or {})
    end
  end
Then, you use it like this:

  Div{id="outer"} {
    Div{id="innerA"} (),
    Div{id="innerB"} {
      Div()()
    }
  }
No compiler extensions needed! And with a bit of library sugar, you could do away with the empty parameter lists too (calling any unresolved functions with empty parameters), but this would lengthen the demo a bit so I omitted it.


In fact, since objects and arrays are one and the same in Lua, one can even do away with the nested calls, which also simplifies things visually:

  Div {
    id = "outer",
    Div {id = "innerA"},
    Div {
      id = "innerB",
      Div {}
    }
  }
This works because when you omit the key (id=) of a table item in Lua, it is assumed to have a incrementing numeric key.


That's very neat. In the pure prototyping language IO, since the syntax was defined as messages to objects, you could define your own syntax to support xml or html directly in IO.

I wonder if Netscape hadn't collaborated with Sun if JS would have had a more pure implementation of prototypes, and how those might have been leveraged more minus all the confusion from mixing in Java-like syntax on top of JS's object model.


I don't have the sources right now, but I once watched (not attended!) a presentation that talked about how JS was initially intended to be a language more like Lisp or Smalltalk, but was changed into an OO language to appease the heavy marketing at the time.


The duo of Lisp and Smalltalk basically define what OO means.

Javascript simulates some of the aspects of OOP in an ad hoc way by turning every object into a hash table so that properties can be tacked onto it.

It's what you implement if it's Wednesday, and the boss asks for a some sort of working OOP system by Friday.


You're right I was half asleep when I wrote the previous comment, I am very sorry. I meant a C(Java?)-like language. Which I am aware has nothing to do with OO, just syntax style.


I think the JSX is just fine as an HTML-in-JS syntax. You can use JSX independently of React. Here's a 200-line library that lets you use JSX as a templating language just like Handlebars: https://github.com/wisercoder/uibuilder


What's the issue with web components that they have never took off?


My $0.02, this was mostly due to historical lagging a more out-of-the-box 'complete' solution like JSX/React, specifically in:

(1) Poor native browser support until recently, Firefox originally refused to support Web Components v0 at all (now called Custom Elements in v1, they are supported in all evergreen browsers mostly).

(1a) Available polyfills were initially buggy and had severe performance issues on older browsers.

(2) Lack of proper templating, though I personally quite adore template literals and approaches like e.g. `lit-html`.

(3) Lack of robust styling API - custom styles felt coarse and tacked on in v0 especially, and were poorly supported by pre-processors like LESS/SASS.

(4) Lots of impedance mismatch issues connecting standard JS/HTML/CSS libraries with the Shadow DOM.


They have taken off. They're widely used for enterprises and design systems, and currently used on ~8% of all page views in Chrome.


Besides the poor browser support (supporting IE11 is still quite a pain) the API is just so bad that you'll need another abstraction on top anyway.

The main use right now is as target for framework independent design systems / component libraries.


Here's an example of a Web Component: https://github.com/wisercoder/uibuilder/blob/master/WebCompo...

Looks pretty straightforward, and there isn't much of an API to begin with. It's just plain HTML, CSS, JavaScript and DOM APIs.


> It's just plain HTML, CSS, JavaScript and DOM APIs.

Exactly. The entire history of web development has been about finding good abstractions around the horrendous DOM APIs.

And that's before you start talking about the need to roll out your own solutions like state management for WebComponents.


I've never had a chance to use it in production but, ClojureScript with Reagent[1] and it's Hiccup-like[2] markup is bliss in this domain.

[1] http://reagent-project.github.io/ [2] https://github.com/weavejester/hiccup


...and, there's nothing particularly preventing a similar approach in JS (keywords would need to be strings, and... data manipulation in JS is relatively a huge pain compared to Clojure)


An interesting native approach; there have been library-based approaches to this that date back a while.

Laconic (https://github.com/joestelmach/laconic) is one of the oldest that I'm aware of, and suffers from some jsquery-ness:

    $.el.div({'class' : 'example'}, 
      $.el.div('content'));

Pithy (https://github.com/caolan/pithy) is another; uses function syntax to get the effect of the tag name. This was discussed previously on hn, https://news.ycombinator.com/item?id=5486239

    html.div('#main', [
      html.h1(null, 'Hello, world!'),
      html.img({src: 'foo.jpg'})
    ]);
In that discussion, there are various other implementations of similar ideas - https://github.com/markgandolfo/el.js and https://github.com/insin/DOMBuilder and https://github.com/jed/domo and so on. el.js came to my attention a long time ago, and I ended up writing a clone that I have used in my personal projects since the library almost writes itself once you steal the basic idea.

Using function application is the easiest way to get the effect of TFA's syntax without the cumbersome overloading of braces.


How far back can we go? insin/DOMBuilder was initially based on a 2006 library of the same - but differently-cased - name by Dan Webb (https://www.webstandards.org/2006/04/13/dom-builder) and the earliest variant I can recall was Mochikit.DOM (https://mochi.github.io/mochikit/doc/html/MochiKit/DOM.html)

By the end of DOMBuilder's life it could generate DOM or HTML from the same code and I'd tried unsuccessfully to implement a way to rehydrate HTML by hooking up events using the same code on the client.

Not long after, I happened to be in the audience for Pete Hunt's React: Rethinking best practices talk at JSConf EU (https://www.youtube.com/watch?v=x7cQ3mrcKaY) and I was totally floored; they'd solved everything I had been trying to do with UI as code and much more, and JSX was the icing on the cake, as using nested object/array syntax has always been rife with comma-management hell when you're maintaining UI code.


Suspiciously absent, but right up this alley is hyperscript:

    h('div', {id: 'foo', onclick: f}, 'Hello')
The benefits of hyperscript over `div()` is that in JS, variable names must be imported by name (so `import {div, ul, li, ...}` gets annoying fast). Also, React is super popular, and hyperscript interoperates nicely with JSX.


FYI in typescript with VS you just hit TAB to auto-complete an import.


What if we had better JS in HTML?

    <form name="comment" onsubmit="event.preventDefault(); output.textContent = email.value">
      <input name="email">
      <input type="submit">
      <output name="output">
    </form>
What if we made function and it was called with target as `this`?

    <form onsubmit="commentOnSubmit(this)">...
    <script>
      function commentOnSubmit(comment) {
        event.preventDefault()
        comment.output.textContent = comment.email.value
      }
I've heard it's possible now with React

    const email = React.useRef(null)
    return (
      <form onSubmit={this.handleSubmit}>
        <input ref={email} />


I like the retrospective of this post! The "what ifs" that could've been taken are fun to think about.

I think I might take a step further than this post does—I think some sort of Racket/Rust-style macro system should be implemented in JS, which means that that means something like JSX could be implemented as a library. There's already been _some_ work on this in JavaScript (SweetJS https://www.sweetjs.org/), but making it first-class would be a big win, IMO.

I know that there are common objects to macros as being too complicated/having poor misuse resistence, but it can (and has!) been implemented and used pretty judiciously all the non-C/C++ languages I've used.


>What if we'd always had something like this in js?

What if html would use round brackets and just use the closing bracket instead of the closing tag?

e.g. <html><body><div>foo</div></body></html>

could be:

(html (body (div 'foo')))

Something similar could be done for javascript. Instead of writing html in javascript we could write javascript in html. Just imagine if we could represent the code as html or in that round bracket form:

function inc (x){ return x + 1; }

could be:

<function name="inc" param="x"><add>x 1</add></function>

or with round brackets:

(function inc (x) (+ x 1))


Congratulations - you've invented S-Expressions! Fortunately for you, there's a whole family of programming languages[0] that are based solely on this syntax!

If you want to see a mature library that uses this syntax to represent both DOM elements and code, I'd suggest checking out Reagent[1].

[0] https://en.wikipedia.org/wiki/Lisp_(programming_language)

[1] https://reagent-project.github.io/


They are proposing the syntax:

    button{id: 'baz' class: ['foo' 'bar'] data: '1' onclick: f
        'Hello '
        em{'there'}
    }
which is of course not possible to use at the moment, but thought I'd convert it to the closest thing that's possible right now:

    button({id: 'baz' class: ['foo' 'bar'] data: '1' onclick: f},
        'Hello ',
        em('there')
    )

Not too far!


In solenya it's very terse - you can use the HTML to JS converter to see the translation is pretty straightforward: https://www.solenya.org/convert

Example code:

    div ({ class: "form-group" },   
      label ({ for: "exampleFormControlSelect1" }, "Example select"),  
      select ({ class: "form-control", id: "exampleFormControlSelect1" },   
        option ("1"),  
        option ("2"),  
        option ("3"),  
        option ("4"),  
        option ("5")  
      )  
    )  
In conjunction with typestyle, you never have to leave js/ts. Very clean.

The arguments against this approach usually boil down to the mistaken notion that "you're not separating concerns". The response is: separation of language != separation of concerns. No matter what you should still strive to reduce cyclomatic complexity. So you're still separating model, view, themes etc. And you're doing so using abstractions within the language, rather than relying on language and file boundaries. Notably in the reverse case, when you have unavoidable links between these layers (since no useful abstraction isn't leaky), the benefits of expressing everything in one language are considerable (e.g. when refactoring).


Reminds me of the “Shakespearean Templates“ [1] from the Yesod web framework [2].

[1]: https://www.oreilly.com/library/view/developing-web-applicat...

[2]: https://www.yesodweb.com/

Copied below to save you a click:

Hamlet (HTML)

    $doctype 5
    <html>
        <head>
            <title>#{pageTitle} - My Site
            <link rel=stylesheet href=@{Stylesheet}>
        <body>
            <h1 .page-title>#{pageTitle}
            <p>Here is a list of your friends:
            $if null friends
                <p>Sorry, I lied, you don't have any friends.
            $else
                <ul>
                    $forall Friend name age <- friends
                        <li>#{name} (#{age} years old)
            <footer>^{copyright}
Cassius (CSS)

    #myid
        color: #{red}
        font-size: #{bodyFontSize}
    foo bar baz
        background-image: url(@{MyBackgroundR})
Lucius (CSS)

    section.blog {
        padding: 1em;
        border: 1px solid #000;
        h1 {
            color: #{headingColor};
        }
    }
Julius (JavaScript)

    $(function(){
        $("section.#{sectionClass}").hide();
        $("#mybutton").click(function(){document.location = "@{SomeRouteR}";});
        ^{addBling}
    });
For those curious, the above is implemented in the metaprogramming framework of Template Haskell.


Does Hamlet produce structured data, or a string?


It produces structured data (the `MarkupM` datatype from `blaze` to be precise [1]).

To check this, note that Hamlet produces `Html` [2], which (when following the link) is defined to be `Markup` [3], which is in turn `MarkupM` [4].

[1]: https://hackage.haskell.org/package/blaze-markup-0.8.2.3/doc...

[2]: https://hackage.haskell.org/package/shakespeare-2.0.24/docs/...

[3]: https://hackage.haskell.org/package/shakespeare-2.0.24/docs/...

[4]: https://hackage.haskell.org/package/blaze-markup-0.8.2.3/doc...


The section on templates should mention lit-html, the modern way of doing this: https://lit-html.polymer-project.org/


This sort of thing is easy in Lisp:

https://edicl.github.io/cl-who/


Or sxml/ssax in scheme.


> I think it's a fine enough solution, but the fact that it's a different syntax from your standard js objects encourages people to consider the VDOM objects as "not normal data", but they are. Notation as a tool of thought innit.

This is the author's only commentary on JSX and IMO it's not enough of a reason to completely ditch JSX. Most people who work with JSX in any reasonable capacity understand that they get transpiled to hyperscript-flavor calls (and ultimately POJOs). I'm not sure why we need to reinvent this wheel in TypeScript as hyperscript already addresses this problem in native JS.


Anyone here worked with Mithril before? It uses that object representation of HTML in JS that this post is suggesting, https://mithril.js.org/


I have a hypothesis about a different way to organize responsibilities within webpages. I think the split of "content" to HTML and "presentation" to CSS was a mistake. To me, those are both describing content. That is, the author's intent to emphasize a particular part of text, whether via <em> tags or CSS, is part of the content.

I think there was a missed opportunity to instead split page layout into its own technology. This would allow for complex layouts, up to and including constraint solving. The browser would calculate the layout, then load each of the content segments into the calculated layout. I imagine it something like ASP.NET master pages, where you can define a page structure with fixed placeholders that can be replaced with other content. Except, of course, this could only specify where on the screen a particular panel exists.

HTML and CSS could then live together in a single technology. I think you could even go a step farther and combine content, presentation, and scripting all into a single technology. Some operators within that technology would have the side-effect of manifesting things on the user's screen. Something based on s-expressions would probably work very well, with its ability to blend code and data into a single format.

I imagine I could probably do some kind of mock-up using iframes to at least demo the idea...


It was not a mistake. The theory being that HTML describes the structure, and CSS describes the presentation. Do not forget, that there are other ways for the page to be rendered: e.g. in screen reader or for print. We had "HTML and CSS living together" with FONT and BGCOLOR and friends. It was not nice. Sad to see people wanting to get it back. We are finally comming to realize that maybe rendering HTML on the server is not so bad after all, when will we realize, that maybe the idea of separating concerns was not so bad after all. And most importantly, when we finally start to learn the technology before trying to "improve" it. It looks like HTML and CSS is somehow considered not worthy learning and understanding, something do be disgusted about. Hating CSS for me sound like the lame bragging "I do not read book" or as the as lame jokes about PHP.


You're grinding an axe that has little to do with what I said.

Your defined split of "structure" and "presentation" is orthogonal to my choice of "layout" and "content". Currently both HTML and CSS define layout and content. Layout being defined as the positioning and arrangement of panels within the viewport, and content being defined as the material displayed within those panels as the author intended. That emphasized part is important.

The issue with styling in HTML had nothing to do with the use of tags and everything to do with the fact that they could not be classed. So the chosen tags had to be duplicated in entirety for every instance, which was a maintenance nightmare. Later versions of CSS saw it become more powerful than the original HTML tags. (Aside: This makes it ironic that it seems to be becoming idiomatic to inline styles for HTML templating. Templating solves code duplication, so it no longer requires classing.)

But the HTML+CSS tools for layout are extremely primitive. There's lots of things to point at here. One simple one is that HTML often has superfluous structure that is required only for the CSS-defined layout to work. A more complex one is that it difficult for me to say I want the footer either at the bottom of the viewport or at the bottom of the content, whichever is lower.


I've thought that Ruby's syntax would map nicely to HTML elements:

   div class: "language-javascript" do 
     a href: "index.html" { img style: "height:2em", src: "pic.png"; "⇦"}
     h1 {"What if we'd had better " + code{"html"} + "-in-" code{"js"} syntax all along?"}
     p{"I have a theory that a grave mistake was made in 1995 ..."}
   end


The object syntax example looks very like what is already possible in Kotlin: https://github.com/Kotlin/kotlinx.html

  html {
    body {
        div {
            a("https://kotlinlang.org") {
                target = ATarget.blank
                +"Main site"
            }
        }
    }
  }


> What about .jsx though?

I think it's a fine enough solution, but the fact that it's a different syntax from your standard js objects encourages people to consider the VDOM objects as "not normal data", but they are. Notation as a tool of thought innit.

This is incidental. JSX can be extended beyond just representing HTML nodes, and IMO has far cooler consequences as first class .bind() notation vs. its current use as an alternate call notation (which already has a notation of course in the form of appending parenthesis to an identifier). Namely, you can begin to curry JSX nodes. For the purposes of discussing HTML specifically, you can do things like:

    const myPre = <pre style = "color:red">;

    <myPre>hi</myPre>
You can actually then take this and end up with a more powerful object notation too (especially for representing tree-like data). I discuss this extensively in my blog post here: http://tolmasky.com/2016/03/24/generalizing-jsx/


The solution is not another templating language. Html is complex and many templating languages exist because it’s hard to compress and everything thinks it’s not that hard. There are so many things you need to do in HTML to make a modern web page that this suggestion conveniently ignores. The web is complex because it has replaced native programs and it’s perfectly backwards compatible. Stop trying to make it look easy.


> There are so many things you need to do in HTML to make a modern web page that this suggestion conveniently ignores.

Any examples of things that aren't handled by the suggested syntax?


Comment nodes, multiple text nodes in one element node, CDATA section.


Are there any examples of where you'd need that in a web application that's just being used to update the DOM?

None of those seem to be necessary to create a modern web application.

I'm not arguing, just trying to understand.


If you have a rich text editor or inline SVG there, you're bound to have to deal with them eventually.


Why? I'm really trying to understand. If you're directly modifying the DOM, why would you need comments or CDATA tags? Is CDATA useful in a DOM if you don't actually need a textual representation?


Are we now reinventing PHP but coming from the opposite direction?


No, this is something different because it understands html.

Php has no understanding of html. It streams the php file as bytes, and anywhere it detects the byte sequence that corresponds to “<?php” it starts executing code instead of streaming until it reaches “?>”. You can stream anything. You can rename a png file to .php and put some php tags in there and it will work. You need something that understands html’s structure to properly escape. Php can’t do it natively, hence the many templating libraries for php.


I get a lot of mileage out of this setup: https://github.com/capnmidnight/Calla/blob/master/scripts/ht...


I have a theory that hindsight isn't even 20/20 when it comes to the web. Hindsight is still 20/400 because we STILL do not know what is the best language & framework. Frontends evolved quarterly with new paradigms popping up at a breakneck pace.

There is a reason why we have knockout, ts, angular, react, vue, and even people touting their own NEW frameworks in this very thread: we still don't know WTF we are doing!

I don't think it is a bad thing, I think we're in the Cambrian Explosion of web development, and will be for decades until the hardware slows down its rapid evolution.

I was there when Mosaic first appeared in /usr/bin during grad school. We had no clue where things were headed then, so I find it a bit harsh to diss on the first devs.


I've been thinking about this for some time now and I totally agree. Maybe not with the implementation but with the idea that we need a better native way of working with markup.

> It would be constantly staring us in the face that our html is just structured data

Not only html, but css too.


In Webact I did a small tagged template literal with createContextualFragment. Very smooth.

https://github.com/enjikaka/webact/blob/master/src/helpers.j... https://github.com/enjikaka/webact/blob/master/src/helpers.j...

  html`<b>Hello world</b>`

returns a document fragment that you can just appendChild with. Super simple.


JS is a procedural language. The somewhat forgotten procedural pattern for constructing these things in procedural languages is to use a canvas::

    xmlCtx = MkXmlCtx()
    SetNsPfx(xmlCtx, "foo", "http://foo.com/ns")
    OpenTag(xmlCtx, "foo:bar")
    SetAttr(xmlCtx, "name", "value")
    Write(xmlCtx, "string")
    CloseTag(xmlCtx)
    xml = GetXml(xmlCtx)
It may look boring but it's exactly the right thing. Syntactic sugar is deceptive. A declarative approach is not the right pattern in JS. (It's essential to XML, but XML is a very different thing.)


This article has a number of problems: it doesn't take into account the primary reason for approaches like VDOM, the history of HTML-in-JS proposals, or the current state-of-the-art in HTML-in-JS.

First, the word "update" doesn't appear in the article at all, and efficient and stable updates are the primary reason that client-side template systems are much more complex than their server-side string-concatenation counterparts. Updates are the main reason why you want to treat HTML as structured, because you can't map data changes to DOM changes without some knowledge of the underlying DOM structure.

Then there's no mention of E4X (or the lesser-known E4H by Ian Hixie). We've had a proposed syntax, so what went wrong and why not revive it?

Again, updates. Creating the initial DOM state isn't that bad. E4X is an incremental improvement over innerHTML. What matters is updates, and the main difference between JSX and E4X is that E4X created _new_ DOM for every invocation, while JSX is typically used to create a new _description_ of the DOM, which is applied to existing DOM to update it.

Any proposal for adding HTML syntax to JS is completely jumping the gun if it doesn't address this point. The syntax matters way less than the semantics on what such markup expressions actually evaluate to and how that result is used to update the DOM.

THen, statements like this:

> This is rubbish for obvious reasons - composing the strings is bug-prone, no typing/linting etc etc. We then have to turn them into elements with the less than elegant:

don't hold up.

lit-html[1] (I'm a maintainer) works very much like this and it excels at composition and turning markup into structured data. The complaint is very much in the vein of complaining about embedding a language into strings and saying that just programming with strings. Well, basically every programming language is just strings, with a defined grammar and tools that enforce and extract the structure. This is no different with embeddings, and JS tagged template literals were specifically designed to make embedded languages more useful.

lit-html uses the browsers HTML parser to parse the strings, enforcing that they're well-formed. It creates HTML <template> elements that are efficiently cloned for new DOM, and it remembers where the dynamic expressions are in the DOM to efficiently update it on repeated renders. It interpolates data post-clone, so it's robust against XSS. It has a plug-ins for VS Code, TypeScript, eslint, and more, for type-checking, highlighting code-completion, and linting of templates.

Which is just to say that string-based templates are a great option that _do_ allow for fast updates, type-checking, composition, and structure, with standard syntax available today.

Finally... there are a couple of recent proposals for JavaScript that affect this area. The records and tuples proposal might make it very efficient to describe DOM in object notation. The block parameters proposal[3], though probably defunct now, proposed adding something akin to Kotlin builders, which would have allowed for the attribute/children structure we need for markup.

[1]: https://lit-html.polymer-project.org/ [2]: https://github.com/tc39/proposal-record-tuple [3]: https://github.com/samuelgoto/proposal-block-params


I actually wish we had more advanced features in HTML itself. There are still many cases today where you only need JS to load something on click or for a simple datepicker.

If some basic things like <input type="date"> and the <details> tag (and associated css) were actually standard, reliable and working, we would not need JS at all most of the time.

I also wonder after 20 years why we still don't have something like <a target="#myDiv"> or <form target="#myDiv"> to dynamically load content rather than billions of specific ajax query scripts everywhere.


I have had this in my toolkit

https://gitlab.com/teknopaul/xgenjs

Gives me neat html in jQuery syntax.

$(...).create("div.foo#my-id/input{type=radio}");

Results in code that is just js, no template needed and no data binding.

$(...).create(...).text(quxx).data("foo", baa);

N.b. create() and most Jquery methods return a nodelist so chaining is easy.

I can work on sets as easily as nodes.

create("input[5]").addClass("btn btn-primary").click(...)

Wrote it years before the framework wars and never got sold on any of them.

I prefer code you can see, but I imagine thats not to everone's taste.


It is said that JavaScript could be Scheme back in Netscape era. It would be extremely straightforward to express HTML in Sexp.

It’s a pity that we didn’t behold this happen.


It would be interesting to see what would have happened with the internet had a few different decisions been made along the way. if a spec had been implemented differently or CSS or JS hadn't become the norm. https://eager.io/blog/the-languages-which-almost-were-css/


Is the author claiming that example is any different than JSX?

https://reactjs.org/docs/react-api.html#createelement

In any case I find JSX quite productive only without React or a VDOM.

https://github.com/ScottORLY/jsx-pragma


What if you left HTML alone?


> the fact that it's a different syntax from your standard js objects encourages people to consider the VDOM objects as "not normal data", but they are.

Can someone help me understand what the author means by this? What are people doing where the author sees them as considering vdom objects as not normal data?


Writing UI's in pure functions is a kind of beauty. It's bit tedious without a framework, but you instead get full control and performance, and semantics. Btw, if your website is just static HTML like in the article, just write it in HTML (skip the JavaScript frameworks).


Ctrl-F `E4X` .... nope.

https://developer.mozilla.org/en-US/docs/Archive/Web/E4X

(Not quite "all along"/1995, but available by the early 2000s...)


QML is this and more.


While being so much simpler at the same time



eh "you must know the rules to break them" I guess.

It's not like JavaScript, the DOM API, and HTML/SGML/XML don't have a very long history of coexistence, including a native syntax for XML-in-JavaScript (E4X) that was however endorsed by Mozilla only, and since abandoned. JSX stands for "JavaScript XML" btw.

> I have a theory that a grave mistake was made in 1995 - the decision not to have a neat, succinct and declarative way of representing html elements in javascript.

I'd have to say this theory is really poorly recherched, then :)


Even in the early 00's JavaScript was a toy. ActiveX and Flash we're popular ways to get real functionalality on a web page.

Ajax and Jquery are what made js generally useable for "app" type sites.


Interesting note is that Perl's CGI module used to have functions like this and they were removed a few years ago because it was considered bad form to mix document and code.


HTML in JS feels so wrong, I'll never get used to React-land. Feels like the simplest 2 page, 2 action apps now need a hundred modules, all kinds of weird naming conventions and config dependency spaghetti and of course a complex build system for what would otherwise be a few lines of plain old JS.

Rails 6 now webpacks 100s of KB of js for a new blank app. wtf if going on.


Yes, it's some weird cargo-culting nonsense for sure.


Personally I find the syntax of SwiftUI to be most sensible.


if this is about react then...xml inside javascript is for scrubs, just rename your createElement to 1 letter (mine is h) and use coffeescript lol.

i also renamed my "className" to "cn" so i dont have to type it but i wouldn't recommend that.

  h 'div',
    cn: 'myclass'
    h 'span',{},"mytext"
    h 'span,{},"asd"


We'd have PHP in the browser.


if php had a html-in-php syntax, that might be true. but as anyone who has ever worked with php and jsx knows, this isn't true


PHP has multiple ways to mix HTML and PHP, that’s part of its design. The simplest way to put a block of HTML inside PHP code is with the heredoc string syntax. As of PHP 7.3 heredocs allow indenting of the closing label, fixing the slight ugliness of heredocs.

You can also just switch in and out of PHP to an HTML block.


Every day we stray further and further away from God

Please people... keep your HTML out of your javascript


JsonML


you mean s-expressions?




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

Search: