Show HN: Use Go's HTML/template to write React-like code
I'm currently working on my hobby project, and one of the fun constraints I put in was to build using as less dependencies as possible.
I chose Go as it has a really good standard library, and all went well for building backend. But for frontend, I was wondering whether I should break the constraint and go for React. I tried options like Web Components, but I really didn't like the ergonomics and I didn't want to use jQuery either.
Out of curiosity, I was exploring Go's html/template package to see if I can write UIs in a React-like manner. I found most of the online docs using the "slots" like approach which I found unintuitive.
But after trial and error, I found an approach that's very close to React and without using any 3rd party packages like templ.
I'd like to share this with the community, not sure if it's a common approach - https://www.sheshbabu.com/posts/react-like-composition-using...
95 comments
[ 3.5 ms ] story [ 161 ms ] threadDidn't realize HN doesn't convert link text to clickable links
For frontend, as in your example, this has the older feel for UI, where each navigation requires a round trip to the server and a full-page response to the client. This is part of the reason people have moved to React and full-stack TS. I love Go, but I'm definitely a big fan of writing webapps in Next at this point. React Server Components are a really nice DX.
I now generate much of the React / Next code at develop time, rather than runtime. Hof's original goal was to make adding a field to a type a one-line change in a source-of-truth file, and then generate all the changes through a full-stack app by running `hof gen`.
Sometimes you get the feeling that you're spending a significant chunk of your time not writing code but fighting with configs and dependency churn.
Using Go's html/template definitely makes the UI feel dated because of re-rendering, but I rarely notice it in my side project. My next exploration is to use HTMX.
I'm planning to gradually add dependencies like HTMX to see how far I can go to reach React's smoothness.
Not being a frontend person first, I have learned to choose whatever they are using these days. It will be hard to hire, onboard, and maintain anything that strays too far for the normal patterns they use.
Next has skyrocketed in popularity for a reason. It makes the React DX much better, losing a lot of the config hell from other framework/library amalgamations
Yes, totally understand it's hard to escape JS in Web frontend. Even writing a simple dropdown requires a little bit of JS.
> Not being a frontend person first, I have learned to choose whatever they are using these days. It will be hard to hire, onboard, and maintain anything that strays too far for the normal patterns they use.
Since this is for my hobby project, it's more fun to be a irrational ;) I use standard React at work.
> Next has skyrocketed in popularity for a reason. It makes the React DX much better, losing a lot of the config hell from other framework/library amalgamations
Need to check Next again, I tried it many years back and it was good.
[1] https://www.w3schools.com/Css/css_dropdowns.asp
[2] https://codepen.io/Ajay-Anand/pen/OJoZjPd
[3] https://bulma.io/documentation/components/navbar/
Those are the most expensive 3 words in the english language!
If I request a page, how does it know to only serve / fetch / render the main content vs the full page?
---
It seems like a lot of would be logic a real language has been moved to DSL and strings, i.e.
https://htmx.org/docs/#swap-options
`hx-on:htmx:config-request="event.detail.parameters.example = 'Hello Scripting!'"`
Not a fan of this fad of moving programming to embedded strings, also seen in lots of Yaml based systems
HTMX sends some headers that help you identify the context, this way you can render just a portion of the HTML (e.g. just the partial of the "Todo" list in your "Todo App" homepage). You need some backend logic to handle that but still much less than a full blown JSON API would have.
They also have extensions that can diff and merge the DOM so even a full page load would replace just what changed, this way your backend is pretty much unaffected (you just end up serving more MBs).
There are other libs in this space by the way, like Unpoly and Hotwire, HTMX just got more mindshare.
> Not a fan of this fad of moving programming to embedded strings, also seen in lots of Yaml based systems
I absolutely agree. I had a comment thread with HTMX's creator about this, I feel like it's a bad idea to shove logic into that. He also created Hyperscript (https://hyperscript.org) so it's something he doesn't think is an issue.
In general I think it's pretty easy to rein that in. Just use HTMX to do most of the plumbing it's strong at (react, fetch, swap) and keep the logic server-side. In my experience that covers the vast majority of web apps. If I absolutely need more client-side logic I'd reach for a little JS code or create a Web Component.
https://cel.dev/
This is a reaction video (sorry) because I couldn't find the original, but in it you see plenty of things associated with SPAs being done in HTMX, from a company that went from React to HTMX: https://www.youtube.com/watch?v=wIzwyyHolRs
Add a few animations and transitions on top and I doubt anyone could tell the difference.
I noticed that the syntax highlighting for the Go html/template examples in the article is incomplete. We're using Go html/templates on a new project (within a team that does a lot of React frontend & some Python) so this kind of project seems like it would really suit, but a massive bugbear has been the very poor IDE-level syntax highlighting support for Go html/templates. Can anyone recommend a good syntax highlighter for Go html/template in VSCode for example? None of the main/official/popular addons seem to get this right.
Seems a pretty unexpected oversight from a language from Google.
Sorry, it might be something wrong with my blog setup. I use hexo, might need to play around with the config.
I use this VSCode extension for coding and it works fairly well: https://marketplace.visualstudio.com/items?itemName=jinlimin...
E.g. (from the article):
See https://github.com/PDOK/gokoala?tab=readme-ov-file#intellij-... for a script to set this up.
When I heard "react" I immediately thought SPA and Event handling in the browser.
This is more close to ASP .NET ( organizing views on the server side).
This is very useful but this is not for handling events on the client.
Thanks again for sharing.
I think apart from vDOM, a big contribution from React is how we organize code.
I was able to build a website analytics project with just 2 dependencies (sqlite driver and bcrypt package) - https://github.com/sheshbabu/mouji?tab=readme-ov-file#philos...
https://news.ycombinator.com/item?id=40491188
But you need to show more interactivity to convince the JS people.
I personally like this style and add HTMX for partial updates.
Haven't thought it all the way through, I expected the code to come out a little bit cleaner but Go being a bit more explicit is for the better, not much one can do here.
But it's a valid idea: 80% of JS component libraries are just reimplementing "<button>" as "<Button>" with no added value atop the HTML.
I think it stems from people who want their links to take on the default button styling, but I'm not 100% sure. Has anyone else noticed this trend at all?
It definitely feels weird to have anything other than text nodes inside <button>, didn't realize it's actually invalid HTML.
I used this approach mainly to have the button component behave as a link button and a form submit button. Here's the actual code from my project - https://github.com/sheshbabu/mouji/blob/master/commons/compo...
What are the drawbacks of this approach? I'm pretty sure I've used this before, can't recall any downsides.
Personally I think the "proper" way to do this would be use just <a> for links, and <button> for submitting forms, and then have the same CSS styles applied to both so that both <button>'s and <a>'s look the same visually if that's what you're going for.
I'm not particularly familiar with Go, but I'd either make the wrapping tag name itself a template variable (maybe an enum between "Anchor" and "Button"? again not familiar with Go) or have two components one for forms and one for links. If I've understood the syntax, something like this?
But given both <button>'s and <a>'s have lots of different attributes to manage its behaviour and state (name/value/type/disabled vs href/rel/target etc) I'd personally split them into two separate components, even if it ends up doubling up some of the logic and styles.> What are the drawbacks of this approach? I'm pretty sure I've used this before, can't recall any downsides.
As others have mentioned, while it's technically invalid browsers will still happily accept it so there's no real issue with it, personally I just find it a bit quirky to read. There's no harm in leaving it just as it is :)
As others have mentioned, the main downside is likely accessibility.
This also explains why there are so few alternative browsers. Writing a new browser that supports everything that happens to work in the major browsers is ridiculously hard.
> This also explains why there are so few alternative browsers. Writing a new browser that supports everything that happens to work in the major browsers is ridiculously hard.
IMO one of the reasons Chrome won was because they supported both Firefox and IE's interpretation of web standards.
I was more interested in finding out where this style had come from really, because I've seen a lot of devs doing something similar and semantically it's just always struck me as a bit odd looking!
thats madness. just because the browser allows it, doesn't mean you should do it.
Hugo, Jet, and other template engines are certainly interesting, but I chose to write in the Go template, which I later migrated to Astro with TypeScript. This was due to the challenges of managing two codebases for a medium-sized site as a solo dev.
The author mentions wanting to colocate templates with logic, Maud allows much tighter/automatic integration in this regard.
This approach also synergizes almost perfectly with HTMX.
Interesting, can you share some examples?
With Maud, templates/components are only defined once, so you no longer have to worry about keeping the two in sync or colocating them.
This is because Maud provides a macro for writing HTML with Rust-like syntax, so all your HTML (components) ends up inside regular Rust files, and you can refer to variables as usual.
This really makes for almost seamless integration between Rust code and the HTML you serve.
I was trying to do the same React-like Component framework, but for Python. No templates needed, you write 100% Python code. Here are some examples how it looks like for simple components: https://github.com/kissgyorgy/compone/tree/master/core/examp...
I use it in a Django project everywhere, no template rendering for custom views!
What are the current frameworks or tools that are popular or recommended for building web applications with Go these days?
I don't think this is "React-like" though. Making components isn't specific to React. We've been doing that since ASP and probably earlier. Your views still need to know what components to render here.
You can go further and just define a template function which takes a template name and a data object. Then render arbitrary children. That way your UI can be fully composed in code and the only thing your components need to know is how to render themselves.
Your page.html file becomes For exampleThe mental load of going from this to
to this or going from this: To, well... case in point, exactly the same thing is just so nice.you're basically saying "I want server side code without having to actually code anything". of course nothing is going to beat react, its an impossible ask
[1] https://pugjs.org/api/getting-started.html
I'm not sure if this I understand the issue correctly, but one can pass multiple arguments, by wrapping them e.g. into a hash (https://go.dev/play/p/89gP42K8XRb):
In my experience, the module is far from a toy, but it's not always obvious how to use it properly, at first.https://blog.logrocket.com/using-go-generate-reduce-boilerpl...
That said, the JS ecosystem is so weird that I totally understand the urge to bail entirely and do things in Go. But JS/TS and all the related frameworks really are decent if you pick a reasonable subset of them.
It actually supports any language, long as you define the lang= name in a config file to tell the compiler how to process it. Ie for python `python="python -m '$'"` would then let the cl compiler know how to handle `<script lang="python">`.