#go
#htmx
Michał Uzdowski
GO + HTMX: The ultimate tech stack for simplicity and speed
Welcome back to Binary Brain, where we take the most complicated concepts, break them down, and add a little humor to keep you sane along the way. Today, we’re diving into an exciting and somewhat underrated tech stack: GO + HTMX. If you’re tired of dealing with complex front-end frameworks and long for the simplicity of good old-fashioned HTML, but with a modern twist, this is the stack for you. So, grab your keyboard, and let’s code like it’s 1999 — only way cooler!
What is GO + HTMX?
Before we jump into the nitty-gritty, let’s talk about what GO and HTMX actually are.
GO
Also known as Golang, GO is a statically typed, compiled programming language designed at Google. It’s known for its simplicity, speed, and concurrency. If programming languages were cars, GO would be a sleek, fast, and reliable sports car that’s as easy to drive as it is fun.
HTMX
HTMX is a small JavaScript library that allows you to access AJAX, CSS Transitions, WebSockets, and Server-Sent Events directly in HTML, without writing any JavaScript. It’s like going back to the basics of web development but with superpowers.
Think of GO as a highly efficient chef in a kitchen, whipping up dishes (backend processes) with speed and precision. HTMX is like a clever waiter who knows exactly what the customer wants and delivers it without ever needing to go back to the kitchen (no page reloads, no complicated scripts).
Why GO + HTMX?
Simplicity
Modern web development often involves a myriad of complex tools and frameworks. GO + HTMX strips all that away, allowing you to focus on building clean, fast, and efficient web applications.
Imagine cooking a gourmet meal with just a few high-quality ingredients instead of needing every gadget in the kitchen. That’s what GO + HTMX feels like — minimalistic, yet powerful.
Speed
GO’s compiled nature and its ability to handle concurrency make it blazing fast. When combined with HTMX’s minimalistic approach, you get a tech stack that’s not just fast in execution, but also in development time.
GO is like the Flash — so fast that by the time you’ve hit compile, the job’s already done. And HTMX? It’s like instant messaging for your web pages, with no refresh needed.
Efficiency
With GO handling the backend and HTMX managing the frontend with minimal JavaScript, you reduce the bloat often associated with modern web applications.
It’s like packing for a weekend getaway with just a carry-on — everything you need, nothing you don’t.
Setting Up Your GO + HTMX Environment
First things first, let’s set up our environment. You’ll need to have GO installed on your machine. If you haven’t already done that, head over to golang.org and get it installed.
Once GO is installed, you can set up your project directory:
mkdir go-htmx-demo
cd go-htmx-demo
go mod init go-htmx-demo
This initializes a new GO module in your project directory. Now, let’s create a simple web server using GO.
Simple Example: Building a Basic GO + HTMX App
Let’s start with something simple — a basic GO web server that uses HTMX to fetch some data and update a part of the web page without reloading.
Create a file called main.go
and add the following code:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/data", dataHandler)
fmt.Println("Server is running on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
html := `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GO + HTMX Demo</title>
<script src="https://unpkg.com/htmx.org@1.5.0"></script>
</head>
<body>
<h1>Welcome to GO + HTMX</h1>
<button hx-get="/data" hx-target="#result" hx-swap="innerHTML">Get Data</button>
<div id="result"></div>
</body>
</html>
`
w.Write([]byte(html))
}
func dataHandler(w http.ResponseWriter, r *http.Request) {
data := "Here is your data, served fresh by GO!"
w.Write([]byte(data))
}
In this example:
- The
homeHandler
serves the HTML page with a button that, when clicked, triggers anhx-get
request to the/data
endpoint. - The
dataHandler
returns some text that will be inserted into the#result
div on the page.
To run the server:
go run main.go
Now, open your browser and go to http://localhost:8080
. Click the “Get Data” button, and watch as the content loads dynamically without any page refresh. This is the magic of HTMX at work!
Advanced Example: Building a GO + HTMX App with Gin Framework
Let’s take it up a notch and build a more complex example using the Gin framework, which is a lightweight but powerful web framework for GO.
1. Installing Gin
First, you’ll need to install the Gin framework:
go get -u github.com/gin-gonic/gin
2. Building the App
Now, let’s create a more feature-rich web application using GO, Gin, and HTMX. This app will include a form to add data and display it in real-time.
Create a new file called main.go
:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Message struct {
ID int `json:"id"`
Text string `json:"text"`
}
var messages = []Message{
{ID: 1, Text: "Welcome to the GO + HTMX chat!"},
}
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.Static("/assets", "./assets")
r.GET("/", homeHandler)
r.POST("/add", addMessageHandler)
r.GET("/messages", getMessagesHandler)
r.Run(":8080")
}
func homeHandler(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{})
}
func addMessageHandler(c *gin.Context) {
text := c.PostForm("text")
newMessage := Message{
ID: len(messages) + 1,
Text: text,
}
messages = append(messages, newMessage)
c.HTML(http.StatusOK, "message.html", newMessage)
}
func getMessagesHandler(c *gin.Context) {
c.HTML(http.StatusOK, "messages.html", gin.H{"messages": messages})
}
Here’s a breakdown:
- We define a
Message
struct to hold our chat messages. - The
homeHandler
serves the main HTML page. - The
addMessageHandler
handles form submissions, adds a new message, and returns the updated message list. - The
getMessagesHandler
fetches all messages and returns them in a partial HTML template.
3. Creating Templates
Now, create a templates
directory with three HTML files: index.html
, messages.html
, and message.html
.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>GO + HTMX Chat</title>
<script src="https://unpkg.com/htmx.org@1.5.0"></script>
</head>
<body>
<h1>GO + HTMX Chat</h1>
<form hx-post="/add" hx-target="#messages" hx-swap="beforeend">
<input type="text" name="text" placeholder="Type a message" />
<button type="submit">Send</button>
</form>
<div id="messages" hx-get="/messages" hx-trigger="load"></div>
</body>
</html>
messages.html:
{{range .messages}}
<div>{{.Text}}</div>
{{end}}
message.html:
<div>{{.Text}}</div>
In this setup:
- The
index.html
file is the main template that includes a form for submitting new messages and a div (#messages
) that dynamically loads all messages. - The
messages.html
file is a partial template that renders all messages. - The
message.html
file is a partial template for rendering a single message when a new one is added.
4. Running the App
Run the server:
go run main.go
Open your browser and go to http://localhost:8080
. You’ll see a basic chat interface. Type a message, hit “Send”, and watch it appear instantly without reloading the page. Every new message is added in real-time, thanks to the power of GO + HTMX.
Explanation of htmx Syntax in the Templates
In the templates for our GO + HTMLX chat application, we used several htmx attributes to handle dynamic interactions. Here’s what each of these attributes does:
1. hx-post
This attribute tells htmx to send a POST request to the specified URL (/add
) when the form is submitted. Unlike a traditional form submission that would reload the entire page, hx-post
allows you to send the data to the server and update part of the page without a full page refresh.
Imagine you’re at a fast-food restaurant. Instead of standing in line and waiting for your turn to place an order (traditional form submission), you send a text message with your order, and the food just appears on your table (using htmx with ‘hx-post’).
2. hx-target
This attribute specifies which part of the page should be updated when the server responds. In this case, the target is the div
with the ID messages
. When a new message is sent to the server and the server responds, the content inside #messages
will be updated with the server’s response.
Think of ‘hx-target’ as telling the waiter exactly where to place your food
on the table. You’re specifying the exact spot that should be updated with new information.
3. hx-swap
This attribute controls how the content returned from the server is inserted into the target element. The value "beforeend"
means that the new content will be added to the end of the existing content in the target element. Other possible values include "innerHTML"
(replaces the inner HTML of the target), "beforebegin"
, "afterbegin"
, "beforeend"
, and "afterend"
.
Imagine you’re adding a new page to the end of a notebook. “beforeend” tells htmx to insert the new content at the end, just like adding a new page to the back of your notebook.
4. hx-get
This attribute tells htmx to send a GET request to the specified URL (/messages
) to fetch data. The response from the server is then used to update the target element (in this case, the #messages
div).
Think of ‘hx-get’ as asking someone to fetch something for you. You send them out with a request (GET request), and when they return with the item (server response), they place it exactly where you asked (update the target element).
5. hx-trigger
This attribute specifies when the htmx request should be triggered. In this case, "load"
means the GET request to fetch messages will be triggered when the page (or the specific element) loads. Other possible triggers include "click"
, "change"
, "input"
, and custom events.
‘hx-trigger’ is like setting an alarm. You decide exactly when something should happen (when the alarm goes off), whether it’s right when the page loads, when a button is clicked, or at some other specific event.
How It All Comes Together
Let’s summarize how these attributes work together in our chat application:
Sending a Message
When the user types a message in the form and clicks “Send” the hx-post
attribute sends a POST request to the server at /add
. The hx-target
attribute tells htmx to insert the server’s response (the new message) into the #messages
div, and the hx-swap
attribute ensures that the new message is added to the end of the existing messages.
Loading Messages on Page Load
When the page first loads, the hx-get
attribute sends a GET request to /messages
to fetch the existing messages from the server. The hx-trigger="load"
ensures this request is made as soon as the page is loaded, and the response (a list of messages) is inserted into the #messages
div.
HTMX is a powerful and easy-to-use library that brings the simplicity of HTML back to modern web development. By using it’s special attributes, you can create dynamic, real-time applications without writing a single line of JavaScript.
Conclusion
And there you have it — your introduction to the GO + HTMX tech stack! Whether you’re building a simple app or something more complex with the Gin framework, this stack offers simplicity, speed, and efficiency that’s hard to beat.
So, if you’re tired of wrestling with bloated front-end frameworks and long for a return to the good old days of clean, fast web development, give GO + HTMX a try. You might just find that it’s the perfect combination of old-school simplicity and modern power.
As always, keep coding, keep learning, and stay tuned to Binary Brain for more tech wisdom, with a side of humor to keep things light. Happy coding!