Posted by mdhb 6/26/2025
Also hard not to feel like this is reaching hard to try and recreate xslt. :( It is inevitable that someone will want to template something that isn't well formed, but can combine into a well formed thing. And then you are stuck trying to find how to do it. (Or correlated entities on a page that are linked, but not on the same tree, as it were. Think "label" and "for" as an easy example in plain markup.)
If I could wave my magic wand, what we need is fewer attempts to make templates all fit in with the rube goldberg that is the standard document layout for markup. People will go through obscene lengths to recreate what judicious use of absolute positioning can achieve fairly well. Sure, you might have to do math to get things to fit, but why do we feel that is something that we have to force the machine to do again and again and again on the same data?
I was never a fan of XML, but XSLT was (is!) a killer redeeming feature of the ecosystem. And it's still widely supported in browsers! It was such a shame that XML caught on where it sucked--configuration, IPC, etc--but languished where it shined, as a markup language with an amazing transformation capability in XSLT.
I think where XSLT fell over was that it's a real DSL, and a declarative, pure, functional DSL at that. People like to talk a big game about DSLs, but inevitably they're simplistic syntactic exercises that don't actually abstract the underlying procedural semantics of popular host languages. When faced with a well-designed DSL that makes difficult tasks trivial... people can't be bothered to learn.
I didn't understand this until I spent a few years going down a rabbit hole asking questions like "why don't people like production rules?" In the case of templating people expect to make a template with a top-down organization that looks like the output, whereas XSLT really wants you build transformations from the bottom-up. On some level the bottom-up part is clear, particularly if you want to code-generate your rules (towards the end I was writing production rules that write production rules) but what is not clear is how the parts all fit together: you can't visually tell between an XSLT that builds the structure you want vs one that doesn't.
I think the most fun I ever had with XSLT was when I used an XSLT engine with user-defined procedures and had them create side effects, such as matching certain patterns in an XML document and making SQL inserts, though that was a long time ago when we were still using terrible XML parsing libraries.
I also have a simple playground for XSLT: https://xsltbin.ale.sh/
But XML's syntax sucks, and so inevitably does XSLT's, because XSLT is just XML. Were it s-expressions, the syntax could suck slightly less. It was (is!) a small price to generate XSLT using XSLT, which makes XSLT very powerful and expressive if you hold it right, almost like a Lisp. This saved me a few times around year 2000 or so.
It was actually great when you got it, but the learning curve was so steep many developers couldn't use it effectively to begin with. For complex pages only certain developers could make changes or fix the bugs. Precisely because it was functional and most developers at the time really only understood imperative.
In fact, I remember the DailyWTF had a WTF about using XSLT as client-side transforms a few years later:
https://thedailywtf.com/articles/Sketchy-Skecherscom
But doing something like that was in fact so much faster than doing it in js, and when you groked it (deliberate throwback), it was so much simpler. I actually wrote a pivot table control in XSLT which completely blew away the performance of the pre-v8 javascript one. Pre-V8 javascript was so slow most developers wouldn't believe you now. A 10,000 iteration loop of even basic operations was often enough to cause IE6 to show a pop-up saying the page wasn't responding.
The pivot table in javascript would crash with just a few hundred lines of data, in XSLT it was instant with even 10,000s.
A really interesting use of XSLT on the web at the time was the WoW character viewer. You could view (and share) your character on Blizzard's website, with all their gear, skills, etc. It was blazingly fast for the time and it was all written in XSLT.
CSS and HTML have a dual relationship. You could certainly write CSS with an XML-like syntax but people would always get confused at whether they are looking at style or markup. Because HTML and CSS look completely different you never have that problem.
XSLT shares the same problem with the RDF specs coming out at the same time that it hid the production rules/logical nature of the system, had it looked more like
<someElement someAttributeattribute=$x/> -> <anotherElement>$x</anotherElement>
it could have been quite different. But production rules never really sold (got told that by the marketing chief of vendor at a hotel bar after a conference they sponsored) and it's an interesting question why. They can do all kind of neat things like manage asynchronous processes that happen over a long period of time (like having a loan officer approve a loan) but nobody ever tried to use them to deal with the async comm problem in Javascript as far as I can tell.When I was looking for my own revolution in software engineering I saw one part of the low code/no code puzzle was that conventional tools force you to determine what order events happen which was something laymen shouldn't be bothered to do. Some counters are: spreadsheets (they figure out what order to calculate it), make (does a topological sort), dependency injection tools like Spring (writing a FactoryFactoryFactory isn't so bad, but maintaining it is a disaster when a "small" change means you have to reorder the order in which you construct everything)
There is a "freedom is slavery" problem here. People saw the semantic web as "you're going to exhaust yourself arguing with people about standards and ontologies before you even start coding" and not "if my data is properly namespace I can throw data from 10 different sources together into my RDF database and start writing queries".
XSLT pattern matching is the plain kind: here is a pattern, look for it in the input and process every match. If some part of the input document is ignored, it's just not useful; if some part of the input document is processed several times, it's perfectly well defined.
The true role of XML are grammar-based notations. These occur in two places: when a human gives data to a machine and when a machine produces data for a human. This is where XML is used despite its often mentioned shortcomings; for example, many notations to describe the user interface are based on XML. This is convenient, because user interfaces are created manually. (I am not mentioning text markup, it is well known.)
Yet XML was often used as a notation for machine-to-machine exchange. For example, the ONIX book description standard. Here data are moved between two computers, yet for some reason they have to form grammatically correct phrases according to a set of grammar rules. Computers do not need grammar. They do just fine with non-grammatical data, like a set of tables. It is way simpler for them; parsing or generating grammar, even explicit, is pure overhead for data exchange and is only necessary when data enters or leaves the computed pipeline.
So, to your examples: configuration in XML is actually fine, but IPC is not. Configuration is written by hand, IPC happens between machines. IPC specification, on the other hand, is also a good fit for XML.
That said, XML and thus XSLT has another flaw: it is way too verbose and has no good way to format it. Conciseness was an explicit no-goal but now we can say it was a mistake.
It didn't help that Microsoft dropped a stick of over-complicated standards that tried to bring RPC into XML. RPC has always been a cursed concept because between (1) trying to be intellectually coherent and (2) caring about performance RPC systems become incomprehensible and it doesn't matter if it is Sun RPC, DCOM, CORBA, "Web Services", Protocol Buffers, etc.
The fact that the "REST economy" is intellectually incoherent and could care less about performance seems to have helped it succeed. Right now I just wrote a javascript function that looks like
const get_item = async (item_id) => {...}
and it does GET /item/{item_id}
and I have a Java function on the server that looks like Item getItem(String item_id)
and is tagged with some annotations that make it get called when that GET request. Jackson lets me write an Item as an "anemic domain object" that gets turned into the exact JSON I want and the only real complaint I have is that the primitive types are anemic so representing dates is a hassle.Granted, it did seem that XML got more heavily abused than some other options for a while. I am curious if that is just a by product of when it was introduced. That or just the general proliferation of how many front end developers we have. (I hate that I am pushing that to almost be a complaint. I certainly don't mean it that way.)
I still can't wrap my head around how the neat and clean dsssl syntax, a real programming language, was replaced by an xml notation for the same: for cuntional code and a framework. because semantically, that's what xslt is: a functional language with a framework, geared at transforming xml instances.
but that syntax... and of course a much inferior and more obscure language than scheme underneath dsssl.
XML needs another syntax that isn't so verbose. Sort of like how OWL has XML, Manchester, Functional, and Turtle syntaxes for the same data structures.
XSLT needs a Turtle-style syntax.
XML in general (the data structure, not the syntax) needs a Turtle-style syntax.
I choose to look at this a little differently.
An XML application using XSLT is so much better (faster load times, faster to write, easier to make correct) than a JavaScript application with a JSON api, that XML is basically a secret weapon.
I only care enough that it stays in browsers, but otherwise I'd prefer nobody know about it because it means less competition on things that matter (faster load times, faster to write, fewer bugs, etc). And I've got a half-baked JavaScript-based "renderer" I can finish in case some Google VP asshat goes looking for things to delete...
How do you come to this conclusion? It seems to me that what you mean is a general gripe with HTML+CSS, not with how it's generated.
And why do you bring up absolute positioning?
I hear this take on HN again and again and sure, absolute positioning has its place, and is needed for many things.
But when it's used for page/app layout, most of the time I came across this it was an absolute nightmare, falling apart at the slightest content (even text!) or screen size changes.
Even print newspaper layout can't work like this, because typography is involved, although it's probably a lot closer to what I imagine you are describing.
Maybe I'm misunderstanding you.
But when I was doing more CSS-intensive work (I still do a fair bit), developing something on a basis when someone created a layout based on absolute positioning that looked like it was "almost ready", it was a terrible time sink to try to fix it and recreating it using flex, flow et al for layout (I'm not that fond of grid outside of some scenarios, and at the time I didn't use it due to browser support) was always faster because the problems with absolute positioning as the main layout tool were basically unfixable.
Maybe there are techniques using calc() and viewport units where it makes sense, but absolute positioning is not suitable for any layout outside of completely static content and viewport dimensions, in my experience.
Basically, my assertion used to be to draw out what you have in mind on grid paper. Then start creating the elements. I don't see how that flow could land you with the 100ish divs that you wind up with on something like a single blue sky post.
Is it a panacea? No. Of course not. Can a constraint language help? I think so.
I'll add that the flex layouts seem like an improvement over what used to be there. Even if I find it rather amusing that we seem to have settled back on tables for layout. :D (I suppose it is more like some of the layout managers from Java days, truthfully.)
But, fundamentally, the problem appears to be that the drop to symbolic text is just not something that everyone does the same way. As such, it is very easy to get into a lot of trouble with the number of cooks in the kitchen, as it were.
It's not that every website uses CSS grid for layout.
Coincidentally, I took a look at the DOM+CSS of a bluesky post just a few days ago (very weird coincidence, since that was the first time I opned bluesky for months), and it did use old-school tricks like centering using CSS transforms, presumably because renders a tiny bit faster than flex centering, or avoids layout calculations when elements are added in a virtualized list.
Virtualized lists are also a good example for falling back to specifying exact pixel positions and dimensions for performance reasons, but these are usually determined with help of JS. I think the transform I saw was a translateX(-50%) one, so centering.
I totally get the canvas-like approach, but in a way the constraint-based flex layouts fall into the same line of thinking for me.
The issue with absolute positioning is the need to manually specify positions and dimensions for elements, which makes it useless unless you are working within a fixed box or only relating to the corners of one rectangle.
It is explicitly meant to remove elements from the normal layout flow so they overlap each other by default.
And don't get me wrong, I don't necessarily want everything absolute positioned. I just find it amusing when people try to get a badge or some such on something and then herculean efforts they will go through to get that badge exactly where they want it.
So, with bluesky, the amount of markup that goes into the footer menu of each post would be what I'm looking at. Tools were clearly used to get styles such as "css-g5y9jx" and this isn't the worst examples I've seen. But I am curious on why so many nested divs seem to be needed all of the time.
I am not clear what you mean by canvas-like approach? I think folks should still use elements. Just fewer of them, all told.
Direct to my claim, though; my argument is just that templates/designs are visual things. I don't think people are thinking in terms of nested div elements. They largely don't even think of sections of their template as parent/child relationships. They have a visual thing and want it filled in with whatever data.
With "canvas-like approach", I meant this part of your comment (not the web technology):
> Basically, my assertion used to be to draw out what you have in mind on grid paper.
I guess we were talking past each other because you equate templates and designs, and I didn't think of this usage of the term (the post also is not about this).
Templating is not necessarily for full pages always, that defeats the purpose of templating languages in the first place to me.
> Direct to my claim, though; my argument is just that templates/designs are visual things. I don't think people are thinking in terms of nested div elements.
Agree. And using modern CSS is a great way to reduce the number of "div"s.
> But I am curious on why so many nested divs seem to be needed all of the time.
I fought many these battles in my jobs, and often it's just for flexibility, because different components are written in a modular fashion. Minimizing the DOM tree size is my goal too, but often the version with less nesting requires a bit more thinking and breaks more easily when elements are added or changed.
CSS gris vs nesting flex containers is a great example for that.
Other times it's just laziness / people don't care.
I took some time to dive into how extensive JavaScript has made the word template in their world. I confess it reads a bit excessive to me. More than a bit, really. Tagged templates, in particular, look like one of the biggest foot guns I've ever seen.
I took it to design because I don't know of any other real reason to template the DOM other than for design purposes. Indeed, reading on the linked proposal, this is to make reactive things on a page. And that will have to be married to a design at some point. Often the entire point of introducing names that are exported from data to a rendered document is for the presentation implications of it. Otherwise, you'd just output the data?
Tagged template literals, aka "template string literals" are yet another technology adjacent to JS and HTML using the word "template". But it doesn't have much to do with the submission.
It's just a fancy name for advanced string interpolation in JS, and has no inherent connection to DOM elements or fragments.
But it is used by some technologies such as styled-components and Lit (the web component library).
styled-components is probably also where the obfuscated CSS-in-JS class names in the bluesky markup originate.
There is also a `<template>` element that is used by ShadowDOM and web components.
But nothing of that is the essence of the post, these are just things that coincidentally use the word "template" (and, less coincidentally, the concept).
As far as I see, it is about the wish to standardize declarative data-binding to DOM trees.
Basically, a React-like API built into the browser, but less detached from native rendering algorithms.
The idea of the post seems to be encapsulated in the web components issue and discussion. Agreed that it looks largely about data binding to DOM trees. To paraphrase you, "seems like advanced DOM interpolation in JS." Which, I just can't bring myself to agree that this looks good. Happy to be proven wrong in time.
the web has the requirement that the 'document' look good no matter what device size/dimension, orientation, and/or capability.
In regular apps (say, a windows app), you don't have this requirement. In mobile apps, there's a standardized set of sizes. Only on web do we have both!
First of all, it's not very nice to laugh in the face of someone advocating for progress on the web platform, which benefits everyone.
Second of all, yes we do now know what good syntax for templating is, it's basically jsx (and I'm saying this as someone who's really not a fan of React). It took the whole web by storm, it's been adapted for all kinds of frameworks, and it's undeniable that all js templating systems converged towards common attributes: templates-as-expressions, composition via nesting and control flow with just javascript (instead of specific template syntax).
JSX is certainly the most popular because it's used in the most popular framework, but it has some very clear weaknesses. In particular, it has very clear semantics for a React-like, VDOM-based framework, but those semantics do not work as well for other kinds of framework.
For example, you mention control flow via ternaries/`.map`. This works great in React, where the entire template will be reevaluated every time any input changes. However, frameworks like SolidJS or Vue in Vapor mode work very differently, and typically evaluate JSX only once at component mount (or at least, as seldom as possible). To support these, these frameworks need to use either special components like `For`/`Show`, or directives like `v-if`.
There's also the issue of how to evaluate JSX. In theory, JSX is flexible, in that `<Cpt prop={expr} />` can be converted to any call of the form `h(Cpt, {prop: expr})`. Again, that's not true for SolidJS or Vapor mode Vue — in both of these frameworks, `expr` cannot be eagerly evaluated, so the traditional transforms just don't work. Both of these frameworks therefore have to include their own custom plugins for handling JSX correctly.
The author's suggestion to also use signals as a state mechanism suggests they're imagining something more along the lines of SolidJS. That's an odd choice (it's my personal go-to framework, but it's also very niche), but it also implies, as discussed, that JSX-in-the-browser wouldn't behave like JSX-in-React. From experience, that will cause problems! I've worked with React developers before who've really struggled to use SolidJS because of precisely this issue.
This is not true. For instance:
Vue uses markup-based templates like this:
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
Svelte uses text-based templates like this: <ul>
{#each items as item}
<li>{item.message}</li>
{/each}
</ul>
Angular uses markup-based templates like this: <ul>
<li *ngFor="let item of items">
{{ item.message }}
</li>
</ul>
And let’s not forget that the world doesn’t begin and end with JavaScript. Most other templating systems are either markup-based or text-based. For instance, Jinja2 is text-based: <ul>
{% for item in items %}
<li>{{ item.message }}</li>
{% endfor %}
</ul>
JSX really isn’t that great. Sometimes it feels like most React devs don’t know how to write a for loop or if statement because they mostly use map(), ternaries, and short-circuiting, which are not very ergonomic compared with markup-based approaches.I'm the last person to vouch for React and the horrors it has inflicted upon web development, but the one thing it definitely got right compared to Angular (and Vue) is the use of JS for control flow, rather than fake attributes and whole new language.
If you’re working on generating markup, it makes more sense to do that at the markup level than constantly switch between markup and imperative JavaScript.
It might use JavaScript for control flow, but does it really count when it uses it in a way that is not idiomatic at all? It’s not idiomatic JavaScript to use map instead of for everywhere, and it’s not idiomatic JavaScript to use ternaries instead of if everywhere. Writing JSX looks very different to writing normal JavaScript.
PS: in modern JavaScript, using map rather than for loops is more idiomatic!
Don’t be silly, the front-end landscape is a lot richer than you make it out to be. React hasn’t “won”, the last time there was a clear winner in front-end, it was jQuery.
> PS: in modern JavaScript, using map rather than for loops is more idiomatic!
No, it’s not, and this is exactly what I was talking about. for loops and map() serve distinct purposes.
for iterates through a series of elements.
map() transforms a series of elements.
It’s possible to use them both for the same things, but there is a very clear semantic difference between them. One doesn’t replace the other, they mean different things.
In the context of “I have a bunch of elements I want to iterate over and output”, what you want is a for loop. The reason why React devs have been convinced map() replaces for loops is that React has to force you into making everything an expression, so instead of writing for when it’s appropriate and map() when it’s appropriate, they have to write map() everywhere.
And yes, modern JavaScript uses tons of concept from functional programming, where it is understood that mutating values and triggering side effects should be a last resort. This is why a good js programmer uses ten times more maps then he uses for loops.
Maybe you don’t know how dominant React is today? Two third of JavaScript developers use React at work (https://2024.stateofjs.com/en-US/libraries/front-end-framewo...).
It feels like you’re out of touch, have you used JavaScript lately?
Output is a side-effect.
> This is why a good js programmer uses ten times more maps then he uses for loops.
This is a) massively overstating things, and b) not relevant to a case where zero for loops can be used.
> Maybe you don’t know how dominant React is today? Two third of JavaScript developers use React at work
I checked those figures before I posted that comment to double-check my memory. Two thirds is not anywhere close to “React won the market”. Android has ~72% global market share, but I’m sure you wouldn’t say that Android has won the smartphone market.
> It feels like you’re out of touch, have you used JavaScript lately?
We disagree, that doesn’t mean I’m out of touch. Try not to be so insulting.
How can you not realize that producing a string or a tree of elements is a purely functional operation? There’s no side effect here. Are you familiar with the concepts of functional programming?
Take “React winning”. We disagree that React won because I don’t think 66% of a market is “won”. But you jumped to the conclusion that I just didn’t know what I was talking about. Then I clarified that the difference in our opinion is not the knowledge of the market share but our judgment of it, and I gave the example of Android not having “won” the smartphone market with ~72% of the market… and you just ignored that and doubled down on calling me out of touch.
Take the use of map(). I am very clearly distinguishing between common usage and defined semantics. The gap between the two was what I was complaining about. But you ignored what I was saying and decided that I don’t know map() is used a lot in modern JavaScript, when that was the core of my complaint!
And for functional programming techniques, we disagree in how we think about the operation. You see it as data processing, I see it as I/O. I very specifically pointed out that I/O is a side-effect. This is a mainstream viewpoint in functional programming. But you ignored what we actually disagree about and assumed it’s just because I don’t know anything about functional programming.
Your approach to disagreeing with me is to ignore half the things I say so that you can attack me for being clueless. You need to do better.
Also, it bears repeating that React isn’t just slightly dominant. 82% of JS developers have used it according to the 2024 State of JS survey, and for good reason. It shaped the modern frontend mindset in a way that Vue or Angular haven’t, despite their own merits. For instance, many frameworks came up with their own version of hooks. It's telling that most new frontend frameworks are aiming for the "better React" position.
I realize we just have different interpretations of what "winning" means in a fragmented ecosystem, but it’s worth acknowledging how much React has set the tone for modern web development. UI as a function of state (and using map() a lot...) is here to stay.
I think you're wrong here. The point at which the rendered template is actually stuffed into the DOM (and hence the screen) is I/O, sure. But the creating / rendering of the template is a pure function, which is what we are dealing with here.
And it is funny, because I can already feel the ideas that would go into templating this symbolically. Characters have 6 and 20 numeric attributes. But, I can already guess most would consider it a fault to manually place either of those on the page. Yes, the sheet has a limitation on how big your name can be. No, you can't really avoid that.
JSX is what happens when you no longer have a design and a dev team. It is great at that, even. But if you have a workflow where a designer makes a template and sends it over to a dev, it no longer really helps. You are much better off making something that can pick at artifacts that are handed off.
Instead, we seem to be aiming for an idea that will have to replace learning of everyone involved.
It's in contrast to the imperative `document.createElement(...)` & `parent.appendChild(...)` APIs which you otherwise use in vanilla JS.
I largely get the intent of what you are saying. But the entire point of why developers use templates is so that they can create pages that meet a design. And the entire reason I think they constantly get redone, is that design is inherently a visual process.
This is like trying to use formatting strings to try and handle localization. It just doesn't work. Folks will try and piecemeal all of the different strings in their application, only to find that some languages don't decompose the sentences in the same way. It can work wonders in small demos. It falls on its face when doing large things.
Don't get me wrong, I'm largely sympathetic to the gripes about the `createElement` and related methods. I've hacked on top of them many times with stuff similar to https://taeric.github.io/cube-permutations-1.html. They aren't pretty. But I'm not entirely clear on why template strings would be largely better?
Further, I could be surprised and this new API will usher in a better way of doing things. I'm not opposed to the effort. I just have a low prior on it succeeding. And I heavily disagree that we know what a good templating syntax is. Quite the contrary, until we learn to embrace visual artifacts, I do not think we will solve the templating needs.
I have no idea what substack and bluesky are, but I'll take that to suggest that someone used templating to create a mess. While that is no doubt true — someone can create a mess out of anything — would the same person have avoided the mess if the templating wasn't there? It is just ergonomics, after all, not some fundamentally different idea.
Do you have examples that are good?
printf("%d", 10);
It might not hold up to today's standards, but "good" isn't a constant.You seem to have gone on a tangent that "good" is a general topic in my question. I meant do we have specifically good examples of templates. Surely if we know what good templating syntax is, we can share examples of it? Even if you can't describe it directly.
So, yes, I understand you are trying to call attention to my 'loosey-goosey' usage earlier. But I am saying that when I said "good", it was relative to the temporal position it found itself in.
Dodging the obvious question in favor of discussing if we can make progress... feels less than good faith.
But, as recognized earlier, others may find it doesn't hold up to today's standards. "Good" is not only not a constant, but is also subjective. Do I really have to explain the entire universe here? Man.
Which is, you guessed it, a language! Okay, yeah, I didn't dive in so deep as to provide a formal specification for the language, or whatever it is you were hoping for, but if you really want to take this to silly town, I'm going to tell you that what you saw is the only valid input for this language and only specify that, so, maybe, unless you are having fun with this comedy routine (in which case, carry on; I'm certainly still entertained!), you can read between the lines? The question asking if I need to explain the universe was rhetorical, implying that I am not going to do that.
The article fails to accept that performance and security aren’t addressed by vanity layers. This is a mistake repeated by web technologies when popular demand eventually crushes common sense, because hiring is more important than training/maintenance when the lowest levels of the work force can’t tell the difference and drives all design decisions.
If you want better performance or security you have to measure things, not wear a pretty dress and look the other way.
This proposal is a good example of how common issues with the platform are solved on top (React etc.) until we recognize them as a problem and then push them down. Polyfills are another example.
If a proposal like this succeeds, it lives a time in the sun, but then spends most of its useful life being the old thing that people are trying to work around, just like the DOM API, just like ECMA versions, just like old browsers, just like every other useful bit of tech that is part of the system but can't be touched.
Is it possible to think about entropy, extension and backcompat as primary use cases?
I want the web platform to have every possible capability that native platforms have (subject to privacy and sandboxing constraints, of course). And I want the developer experience of web developers to be incredible.
But these need to be balanced against the consequences of added complexity. And in this case, does native templating really improve developer experience? I'm not convinced the benefits outweigh the costs.
I dunno --- getElementById has been stable for, what, 25 years? "There's no such thing as a stable API" is something said by people unable or unwilling to create interfaces that last. It's a statement of personal resignation, not cosmic impossibility. There are tons of counterexamples.
Application needs, like other needs, are infinite. You satisfy these needs by adding new APIs, not breaking working ones.
At the same time I don't think there is actually anything that most people would consider an API that is open to public usage that has maintained that kind of stability that getElementById has, which after all is something most people would describe as a method of an API.
On the web they are. Once something is out in the open on the web, there will be people depending on this, in this exact form, forever.
That's why there are still APIs that end up in "smooshgate" because of decisions from 20 years ago: https://developer.chrome.com/blog/smooshgate
But in the process, the base functionality has been propped up another level.
Incremental updates aren't worthwhile just because of userland requirements that will always discover new gaps, use-cases and blindspots.
I can't even begin to imagine how much CPU and bandwidth is wasted with billions of users downloading, parsing, and executing something like React.
DOM sucks though, it's slow, it's heavyweight, it lacks transactions. We're stuck with it, and frameworks like React have to do the DOM diffing + patching thing, explicitly, in JS.
2. We're currently living in 2025. React (and SPAs) is not even slightly necessary.
Alex Russell has written swathes of arguments about Reacts performance issues https://infrequently.org/2024/11/if-not-react-then-what/
The DOM has become much faster since React started over a decade ago, the VDOM really isn’t needed anymore even for app like experiences
React is about developer preference over user experience
(I'm still of the sort that thinks Signals are just worse Observables, so it's not a proposal I'm particularly thrilled about, but were it to be adopted Signals are easy to use in Observable contexts as well, they are just uglier half-implemented BehaviorSubjects, though maybe with a few extra lint rules to prefer Observable behaviors over Signal ones.)
React lets you return dynamic tree structures and insert code anywhere inline in that structure. Most templates explicitly don’t allow that for good reason. Further, most but not all templating frameworks have special syntax for conditional logic and loops.
If JSX is templating then templating has no meaning. Would createElement() be a template? In that case all functional programming is.
I get why OP likes signals. In every large enough project there is a half baked implementation of a DAG calc tree and it makes sense that a language could standardize one.
But these abstractions have a huge mental / implementation cost.
The problem, as with most engineering things is a tradeoff problem. The react model - where you just update the global state and re-render everything - is slower but easier on the brain. The signals model is faster, but so much effort.
Most apps out there don’t need to be crazy fast, and people will choose react because it’s just simpler.
But signals don’t really have anything to do with templating, do they? So why do we have to choose, could we have templating and signals as separate things?
Well OP thought about templating and realized you do need a way to tell the dom how to fit your templated node where it belongs and update it when things change.
And this is where these proposals fail. There needs to be a choice here. The API must pick a side (well technically it could allow for both, but ugh), and developers won’t ever agree which side it should go.
The big problem of UIs has always been how they update, not how they’re defined. Microsoft tried (and failed) at defining a ton of models, MVC, MVP, MVVM, and what not, all of them were painful AF. Then imgui come and say, well what if UIs didn’t have state at all. Ooh this is nice, but kind of hard on the cpu, so what do we do?
Well, perhaps one of the biggest reason for the success of web apps is in fact that the dom didn’t impose a way to bind data to its view. And so we may be doomed to framework hell.
there are multiple frameworks now that do fine-grained diffing without relying on signals, proxies, or any other reactive primitives. they basically have the top-down react model but much faster and without the weird concepts like hooks and manual/wasteful dependency arrays.
my favorite one is ivi-js: https://github.com/localvoid/ivi
it's just 8% slower than the fastest / ugliest / imperative / unmaintainable vanilla js you can eventually arrive at if all you care about is winning benchmarks.
https://krausest.github.io/js-framework-benchmark/2025/table...
One of the most useful features that could make a lot of incremental computation problems easier is "value types"[1], but unfortunately it seems that isn't going to happen anytime soon. The biggest constraint when developing an efficient UI framework with good DX is JavaScript. Also, it would be nice to have `Node.prototype.insertAfter()` :)
for perf, s/JavaScript/DOM, i think.
good DX comes from ecosystem and amount of time invested in making good tooling. JSX would be a non-starter without IDEs helping autocomplete, linting/format, syntax coloring, and webpack/babel to do the compilation.
tagged templates could reach at least the same level of DX as JSX if the community invested the resources to make that better. i'm not saying it's the right solution for a standard, but it would be way better than jsx, since tagged templates are already a standard.
and then you immediately go on to say this:
> tagged templates could reach at least the same level of DX as JSX if the community invested the resources to make that better.
So, tagged templates are also non-starters without IDEs helping autocomplete, linting/format, syntax coloring.
> i'm not saying it's the right solution for a standard, but it would be way better than jsx, since tagged templates are already a standard.
They are strings. There's no magic in tagged templates that somehow make them immediately better for some custom non-standard syntax compared to JSX.
You can't just plop a string containing lit's custom non-standard syntax into an IDE (or a browser) and expect it to just work because "it's tagged templates are standard".
For the purpose of templating in the browser there's literally no difference between standardizing a custom syntax based with JSX or tagged templates.
they're marginally better since they have a platform-defined way to deliniate static from dynamic parts. ivi _can_ work without a runtime or build-time JS parser, while JSX cannot (because jsx has to be parsed out of full blobs of js)
on the dx/ide side, sure there's not a huge amount of difference if both had the same effort invested.
My feeling is that tagged templates would actually be a worse fit in this scenario because now you would have to distinguish between "regular" tagged templates and "templating" tag templates.
Personally, I don't think that it will have any significant impact, everyone will continue using React,Vue,Svelte and it is highly unlikely that they are going to adapt this new API.
Microsoft used those at various times, but the only one it defined was MVVM.
MVC was Xerox PARC, MVP was Taligent.
I would gladly take easier on our hardware, bandwidth and planet even if a bit harder on the developers' brains. (as a developer).
> Most apps out there don’t need to be crazy fast
I wish we recognized that we need apps to be lean.
> and people will choose react because it’s just simpler.
I think you are right, and I dislike React for this.
The actual semantics for templating and data binding could just be a set of standard functions that use those syntactic feature, much like what you see in Jetpack Compose.
In fact, we could have that cross-language.
by one of the people wrecklessly barging forward with half-baked specs that introduced significantly more problems than they solved, pushed a "solution" that requires 20+ new web specs to barely do all the things user-space is already doing while completely ignoring and gaslighting anyone who wasn't 100% on board with what they were doing.
Safari argued that there should be a declarative ways for this 15 years ago
<pedantic>
It's "recklessly". "reck" is a very old word meaning "to care, heed, have a mind, be concerned about"; so "reckless" means "without taking heed".
I actually thought it was directly related to "reckon" (meaning "to think or calculate"), but when I looked it up it turned out not to be the case (except much further back in the etymological tree).
</pedantic>
My brain knows it "reckless", my fingers type "wreckless". Same happens to a few other words, too.
My feeling is that they were focused on designing something that is aimed at building form controls, not the kinds of components web developers use in practice. They are designed to make browser vendors’ lives easier, not web developers. That’s often excused with “web components excel at ‘leaf‘ components” when what is actually meant is “web components are bad at everything else”.
I would expect an actually good solution that fits in with the web’s architecture to come from the direction of HTMX, not web components.
> Safari argued that there should be a declarative ways for this 15 years ago
True, but they were equally able to propose and deploy alternative solutions and mostly just went along with web components (with exceptions of course).
Safari doesn't have as many engineers (a shame) and definitely doesn't have as many people whose apparent job is just to sit on standards committees and generate specs (like Alex Russel, Justin Fangnani etc.).
They did end up proposing declarative template instantiation in 2017: https://github.com/WICG/webcomponents/blob/gh-pages/proposal... but that mostly went nowhere
It really is a shame Apple don’t invest more in WebKit and the web standards process. Although they’ve been doing a lot better over the past few years.
<my-component>
<template shadowrootmode="open">
<style>
::slotted(*) {
font-weight: bold;
font-family: sans-serif;
}
</style>
<slot></slot>
</template>
<p>content</p>
</my-component>Or that their mere existence infects nearly every spec in existence delaying and needlessly complicating actual useful specs like Scoped CSS?
- doesn't require 20+ web specs
- doesn't forget and then scramble to fix the most basic expected functionality like form participation
- doesn't pollute the space so badly that actual useful specs like Scoped CSS are delayed for years because now they have to deal with all the web coponent shenanigans
- hopefully doesn't take 15 years to barely do what others have been doing since time immemorial
<!DOCTYPE html>
<title>Example</title>
<cool-dog>
<template shadowrootmode="open">
<style>
:host {
display: block;
font-family: system-ui;
margin: auto;
width: fit-content;
}
::slotted(img) {
border-radius: 1em;
}
</style>
<slot></slot>
</template>
<img
src="https://placedog.net/512/342?random"
width="512"
height="342"
alt="A dog"
>
<p>Check out this cool dog!</p>
</cool-dog>
<script>
customElements.define(
"cool-dog",
class extends HTMLElement {},
);
</script>
First off, what’s with the pointless JavaScript? There’s no need for imperative code here. All web components have a dash in the name; this can be inferred. But even if you want it to be explicit, this could be done with markup not imperative code. But no, it doesn’t work without the pointless JavaScript ritual.Now, I’ve noticed that since the text is a caption for the image, I should actually use <figure> and <figcaption>. So let’s do that:
<!DOCTYPE html>
<title>Example</title>
<cool-dog>
<template shadowrootmode="open">
<style>
:host {
display: block;
font-family: system-ui;
margin: auto;
width: fit-content;
}
::slotted(img) {
border-radius: 1em;
}
</style>
<slot></slot>
</template>
<figure>
<img
src="https://placedog.net/512/342?random"
width="512"
height="342"
alt="A dog"
>
<figcaption>Check out this cool dog!</figcaption>
</figure>
</cool-dog>
<script>
customElements.define(
"cool-dog",
class extends HTMLElement {},
);
</script>
Wait a sec! The nice round corners on the image have turned into ugly square ones. Why is that?It’s because web components can’t style anything other than their direct children. You can style the <img> when it’s a direct child of the web component, but as soon as you need anything more complex than an entirely flat hierarchy, you run into problems. Even if it’s something as simple as wrapping an <img> in a <figure> to associate it with a <figcaption>.
What’s the “official” way of getting things like this done when you bring it up with the people working on the specs? Make a custom property to fake the real one and then set a global style that listens to the fake property to set it on the real one:
<!DOCTYPE html>
<title>Example</title>
<style>
img {
border-radius: var(--border-radius);
}
</style>
<cool-dog>
<template shadowrootmode="open">
<style>
:host {
display: block;
font-family: system-ui;
margin: auto;
width: fit-content;
--border-radius: 1em;
}
</style>
<slot></slot>
</template>
<figure>
<img
src="https://placedog.net/512/342?random"
width="512"
height="342"
alt="A dog"
>
<figcaption>Check out this cool dog!</figcaption>
</figure>
</cool-dog>
<script>
customElements.define(
"cool-dog",
class extends HTMLElement {},
);
</script>
Now let’s say I want to put a second <cool-dog> element on the page. What does that look like? You define the template once and then just use <cool-dog> a bunch of times? That would be the obvious thing to do, right? Since it’s a template?Nope. Every instance of the web component needs its own <template>. The best you can do is write some JavaScript to copy the template into each one.
The developer ergonomics of this stuff is terrible. It’s full of weird limitations and footguns.
Exactly, I'm not sure why you've included the JS. The whole point of the Declarative Shadow DOM is to create shadow roots declaratively, rather than imperatively. To quote web.dev "This gives us the benefits of Shadow DOM's encapsulation and slot projection in static HTML. No JavaScript is needed to produce the entire tree, including the Shadow Root." [1]
[1] https://web.dev/articles/declarative-shadow-dom#how_to_build....
It's a pipe dream that doesn't work in practice. Because on its own declarative shadow dom is useless.
The example I was responding to was using the Declarative Shadow DOM. My comment was intended to point out the simple fact that the imperative component definition the author was complaining about is superfluous, meaning you can safely remove that entire script from the example.
DSD is useful for SSRing web components, which allows them to render and work without JS. But honestly, I don't get the obsession with doing stuff without JS, it's part of the html/css/js trifecta.
22 items: https://w3c.github.io/webcomponents-cg/2022.html
In those things like ARIA are not a single spec. It's now close to five different proposals and a huge ARIA Object Model proposal.
Similar thing with Form Associated Controls: it's not one spec. It's a bunch of specs fixing idiotic issues like this: https://github.com/WICG/webcomponents/issues/814
Note: easily half of these only exist because of web components and for web components. Literally nothing else has these issues.
I think the reason is because the DOM is a leaky abstraction and at some level I would just prefer last write wins.
I realize declarative templating is supposed to handle that, but this starts to break down really quickly when you share mutable state between components.
Second, what can you do with imperative control of the DOM that is less practical with the declarative one? I can only think of certain methods (attachShadow(), showModal()) but even then you're a 10-line component away from making it declarative.
AFAIK Ryan Carniato/Solid JS is still exploring what’s possible with signals. I don’t think userland exploration of this space has entirely finished, and further innovation may be possible.
It will be near impossible to get everyone to agree on a standard template system. What the browser CAN do, however, is provide some lower level APIs on how to apply diffs to the DOM in a performant native way.
I would LOVE for something like this to exist in browsers natively:
element.applyDiff(DocumentFragment | string, { method: 'innerHTML' | 'outerHTML' })
This could apply the diff in a way that would be non-disruptive, i.e. it would keep element focus, input values, states in audio and video players, mutate attributes, etc. There are JavaScript libraries that do this like Idiomorph, but a native solution has the potential to be much more performant.
That proposal hasn’t just stalled, it’s been withdrawn. https://github.com/tc39/proposal-record-tuple/issues/394
It has been replaced by https://github.com/tc39/proposal-composites