Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Declarative Enhancement for HTML (twinspark.js.org)
123 points by revskill on July 6, 2023 | hide | past | favorite | 55 comments


It reminds me of hyperscript: https://hyperscript.org/

I am fine with writing a little js has long as it's colocated with the (augmented) html and css. I think the svelte approach scales better and seems more easily debuggable because it enforces a structure and is more readable. There is enough stuff in my html tags already.


Actions are somewhat similar, yeah, even if much more limited.

Svelte was too js-heavy, and it requires js backend to be rendered on the server - while we had no js engineers. Plus markup was already done, as we rendered it server-side when using React.


Nit: SvelteKit requires a backend on the server (actually it does not you can use it only for the client side rourting and have no SvelteKit backend and talk directly to your own backend) but Svelte does not as it is just a superset of html. Even when using the SvelteKit backend you can disable server side rendering.

But sure I trust you that the htmx way was the way to go for your use case/situation


It would be great to have some examples right on the main page as many devs would be interested in how this library compares to the React/Vue/Angular/etc. Currently, the code samples are hidden two levels deep and behind a view source button.


Thanks for that message, it was just hard for me to decide on what to put in there :)

But your comment forced me to, so I've put something in there, even if it's not really thought through. :)


Could be a todo example with a static json as API ?


There is no way to render JSON as HTML right now, it expects server to return HTML.

OTOH that's an interesting thought and it feels like just an addition of one command to whatever there are in actions ( https://twinspark.js.org/api/ts-action/ ) right now... I need to think about it a bit. :)


An action that renders HTML from JSON will either:

— Require additional client-side templates and then it's back straight to hell;

— Require really specific JSON structure, basically HTML-in-JSON, which will be ugly as hell and totally meaningless. Meaningless, because then it means I need to adapt my API to this format, and then I can just make it return HTML.


Yeah it’s only the first way, since the second is effectively the same as rendering html on the server.

As for the first - it could give a way to use legacy apis and static data. Not sure if I want this in the core, but… how hard can it be?


Sure, if it's only one additional five-liner action that's not even in core, then whoever wants to bring the hell back - it's only their own doing


I have been thinking for a while to create a new library/framework that composes the features of Tailwind/DaisyUI and HTMX/Unpoly/Hotwire into a SwiftUI like declarative template language (forcing these features into HTML attributes makes HTML bloated/difficult to write) that eventually generates all the HTML, JS, CSS code in the background.

I am tired of MVC frameworks, SPAs, writing CSS, JS, dealing with tooling, setting up IDEs to format the code properly, etc, I just want to create nice webapps, and want my app designed nicely from the first line of code I write.


> I am tired of ... writing CSS, JS

Wait till you get tired of writing html - and you will have caught all the pokemon :-)


have you thought about low code platforms?


Why would I? I didn't say that I don't want to write code, but don't want to deal with this frontend madness. Other platforms (Android, Swift, desktop, etc), has been able to solve that the web hasn't been able to do in 30 years.


I on the other hand find that "npm create vite@latest" is orders of magnitude simpler than working with any of the Android or iOS developer environments. I can't speak to "desktop" as I haven't done anything like that in 10 years, but I have a feeling that it would be similar.

Could it perhaps be that you are confusing familiarity with simplicity?


Please show me how Vite helps you to work in one language instead of three.


CSS is a feature, not a bug


How does it compare to HTMX? Anybody have experience with both?


That was the first thig I wondered too.

In case you didn't spot this part:

> Some reasons why TwinSpark exists despite HTMx and Unpoly (those are similar in approach):

>

> It’s really small (8KB .min.gz).

> There is no attribute inheritance — keeps surprises away.

> Batching - very useful if you want to use HTTP caching effectively, while maintaining some personalisation for your users.

> Bundled - a lot of practical stuff packed in, like actions, or non-traditional event triggers, or morphing.

> Extensibility - you can easily register new directives the same way those in core are registered.


Most of these also apply to HTMX it seems.

I think a bigger difference is that TwinSpark seems to have some integrated DOM manipulation, so it's a bit bigger in scope and less opinionated?

HTMX on its own is great as long as you stay within its philosophy of rendering things on the server.

But most UIs I write need - as in it's optimal for UX and performance or out of necessity because it's talking to a third party - at least _some_ parts to be fully client side rendered.

I personally found that combining HTMX with something like lit-html is kind of the sweet spot for a lot of projects assuming full-stack development. These are very small/light libs that cover a ton of ground with minimal surprises and very good performance per default. The _only_ downside is that you don't get isomorphic rendering code but I happily pay that relatively small cost for having such a simple dependency graph.


Why do you feel the need to use lit-html? Just interested in the use-case.


I am not the original poster, but I use lit-html to make the interactive elements on the page like tabs and modals. Then I use HTMX to load the contents of those elements when the tab or trigger is clicked.


That's one of the reasons TwinSpark got actions, you still need little bits of client-side interactivity.


I find things like actions is great for conditionally showing and hiding form fields or small things like that, but if you want to have accessible tabs and modals it is best to bundle it up in a component. Here is an example of a lit components I use, https://codepen.io/megaman821/pen/GRXmzZb and https://codepen.io/megaman821/pen/dydvxBE


This doesn't answer the question "why not bring this inside htmx or unpoly", and now as a developer I need to again check if I need to port over a new framework or not


Two reasons really: I wrote it before htmx appeared, so it already existed and a few projects were using it in production. And second one - I really hate attribute inheritance, and it’s everywhere in htmx…


The blog post hints at the first point, but I didn't know about the latter, so thanks for the details !


> now as a developer I need to again check if I need to port over a new framework or not

Why do you "need to"? Use what works for you. Glance over new stuff and dig deeper if some aspect of it appeals to you. And if the churn stresses you out then don't.


When do people understand "declarative" is a style not a property of some language? As the language, "declarative" xml and by extension, html has failed in every single platform (the web, android, iOS), which is why in all of those platforms people have been trying for years to write UI in code, but in a more declarative style (React, Swift UI, Jetpack Compose). This is backward.


Strictly speaking I agree with your first sentence, but clearly some languages/environments lend themselves more to the declarative style than others, and may or may not let you reap more of the benefits. (I also disagree that HTML has "failed" in almost any sense, but I don't think that's as interesting a discussion.)


Sorry you said not interested but I have to comment on this

> disagree that HTML has "failed" in almost any sense

The web was born in html, at some point web development skill shifted from it to mostly js. Why do you think that's the case if not html itself failing to accommodate for modern web development requirements?

It's not a joke that html isn't a real programming language. You can only go so far with it and it definitely offers zero help in modeling the problem's domain or any high level thinking process that programming encompasses.


Even so, web developers always had the option of sticking with an imperative approach to UI, like using element.innerHTML = '...', but overwhelmingly they preferred more declarative solutions like React. You could just as easily make the argument that the shortcomings of HTML had nothing to do with its "declarativeness", since that part was retained. I think a more likely explanation is that HTML couldn't be used to express the more complicated SPAs that people wanted to build, and regardless of what you think about those, JS-based solutions had to fill that need.


Yeah, HTML is declarative but the issue is that it’s such in an extremely simple way.

Loops, conditions, and variables/transclusions are table stakes, and without them pure HTML is just tedious data entry with extra tags.


> at some point web development skills shifted from it to mostly js.

[citation needed]

I mean, it looks like this if you look at HN (the comments, not the code) and similar places, but imo less in the wild.


You and I can both claim opposite things without citation, but we both know which is closer to reality based on what skill is on demand in the job market and what's LOGICALLY required to make web apps with such and such capabilities.


Declarative markup always evolves into a badly conceived programming language.


I think in one direction, i.e. templating, it works fine. Have data, have declarative syntax on how to iterate over data and generate fresh code from that.

The bidirectional case is already difficult where your changes in the generated source should backtranslate into changes in the supplied data.

But now also declaring interactions in the general case? This endeavour must surely fail, as there are so many possible interactions and so little design space without running into either the inner platform effect, where you're just replicating the host programming language (but with bugs), or Greenspun's tenth rule of programming, where you're accidentally building "an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp".

As an aside: I think a sweet spot is providing some UI elements and a framework for composing them, and then having a kind of DSL to low-code-connect them up in the DOM. You can abstract a lot of stuff away from the end user using, you know, code. And then the DSL can be nice for the interactions.

But we all know that interactivity is hard and complex and no way of writing it down, be that imperative, declarative, or whatnot, will take that away.

Edit: Beware of the Turing tar-pit in which everything is possible but nothing of interest is easy.


That's also been my experience, yet I've also gotten a spaghetti of a mess assembling the UI in regular code with loops and whatnots. Are there any other interesting options I could explore?


Declarative Code for initial state, with modifications done in regular code. Ideally data bindings for lists etc. (so the declarative part can state "this is a scrollable list view, each item looks like this, the content of these items is stored in variable Y", and any update to Y updates the list)


an imperative language that is DSL-friendly, such as kotlin and jetpack compose, or just functional languages, like ClojureScript's Reagent.

JSX is fine too. It's gotten a lot a bad rap because of React, but looping and conditions have never bothered me, despite people's complains about them.


I wouldn't go so far as to be bitter about it like you appear to be (based on past negative experience?) but yeah: the real question is why should one stick to markup when you're developing an app anyway?

Markup is for documents, and the "declarative" aspect of it is that it guarantees certain safety conditions (termination, injection safety, maintainability) without sending the author into a full Turing-complete programming environment and everything that goes with it, requiring experience, testing, choice over implementation alternatives, maintenance, debugging, and more laborious/expensive hosting with monitoring, etc. Markup is for ambitious tech-savvy end users/non-developers, and the high end of a non-Turing markup language operating purely at the level of syntactic manipulation, unlike htmx and TwinSpark, IMHO would be SGML, containing a finite state mechanism for context dependent styling or other processing and natural injection-free templating/macro expansion.

Now the web has pushed the limits of what can conceivably be called "documents" eg blogs with threaded comments, table of contents and other navigational idioms, etc. For these kind of "content apps" (supported by SGML still), there has always been a struggle between full Turing complete environments and increasingly idiosyncratic markup techniques.

That struggle is even more noticeable when looking at CSS. IMO, CSS has aggregated such an enormous complexity while most advanced use cases fall straight into "app" territory. That is, there is no justification for most recent CSS features when those features can only realistically be applied in the presence of JavaScript anyway, and thus should actually be implemented using JavaScript rather than bloating CSS. Case in point: the has() selector which doesn't materially enhance what you can do with HTML/CSS but clearly is introduced in support of components and modularity; ie requiring JS anyway, and with JS allowing much better modularity already anyway, is hence just redundant. Clearly, also calc() and custom properties are doubling what's already available.


I think my experiences are just very different from yours, but I found that declarative markup was the only sane way to represent visual UI elements. The classic example is using an imperative JS API like element.innerHTML = '...' vs React/Vue/etc, but the same could be said for newer UI APIs, like SwiftUI. I wouldn't call a mobile app's UI layout a document, but I still think the declarative nature of that API is a better fit than its imperative predecessor, UIKit.

Both of those examples have an "escape hatch", where you can drop into an imperative API if you need to, so I can see the argument for them not being a perfect abstraction of the underlying primitives, but that doesn't mean they're not useful and a good fit for the problems they're solving.


The has() selector definitely enhances what you can do with CSS. You can style elements differently based on what they contain.


which is the wrong way to do it. The source of truth for a state, that determines the style, should be... well a state, most likely in memory. It should not be a visual representation of that state (what element is rendered in side). When you change the latter, your conditional css will become broken unknowingly.


Even more to that point we only need HTML (in any flavor) because the browser says we do. The compile target is the DOM. The DOM is the goal, not HTML. If the environment were treated more like WASM where any language could compile to the target then it wouldn't matter what the source language is.


I imagine rendering a website to be much faster if the initial render is just streaming bytes from the network into the browser runtime, instead of parsing some string.


Having a standardized data representation is a good thing.


Does it really matter? The data representation could be markdown, yaml, JSON, SVG, or just about anything else and be equally effective. The browser already supports XML and HTML5 as wildly differing grammars that still compile to the same target.


html is not a DATA representation, it's not designed that way and it would actually be way more noisy if attemps to represent all the hidden states of the DOM.


Would be interesting to see the HTML spec find a way to pull from the SCXML[0] spec for declaratively modeling nested, parallel state machines, maybe adding pseudo-selectors to CSS for querying it.

[0]https://www.w3.org/TR/scxml/


Is the name in any way associated with the two spark plug Alfa Romeo engines?


Yeah, that was the inspiration. If you know, htmx predecessor was called intercooler.js, so I just continued the automotive theme. :)

I had a reference on main page for a long time...


How does this differ from Alpine? It looks like an AlpineJs 2.


It's more like an alternative implementation of htmx. Alpine is more about "let's do components in HTML", and this one is more of an idea "how do not go there, but still have practical results". :)


Looks awesome, can’t wait to try it out!




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

Search: