HTMX - Navigation Methods

When working with web applications, it’s common to navigate between different pages. It’s one of the basic parts of a web application. While using HTMX, it offers a few ways to achieve navigation between pages. Let’s explore them. hx-push-url attribute ( client ) This attribute is used to push a new URL to the browser’s history. This will change the URL without reloading the page. <a hx-get="/about" hx-push-url="true">About</a> or <a hx-get="/about" hx-push-url="/about-page">About</a> Hx-Push-Url header ( server ) We can also use Hx-Push-Url header to push a new URL to the browser’s history. This will change the URL without reloading the page. ...

HTMX - Trigger events from Server.

When using HTMX is a common pattern to write event based actions or ui updates in the client side. It’s a good practice to use javascript as event based scripting system in our client side code. Some events from the server might be required in client side to update the DOM or to trigger some actions. A common pattern to achieve this is to respond a header Server-Event with a value holding the custom event and then using javascript, you can handle the custom event. ...

GO + HTMX - A Crud implementation

As I was exploring htmx, I wanted to try out an interactive workflow with it. A classic example is a data list, modal to create / update data and a delete. Setup with Gofiber Initialize go module and install dependencies go mod init htmx-crud go get github.com/gofiber/fiber/v2 go get github.com/gofiber/template/html/v2 Setup Server html template engine main.go package main import ( "log" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/log" "github.com/gofiber/template/html/v2" ) func main() { // Setup html template engine engine := html.New("./views", ".html") app := fiber.New(fiber.Config{ Views: engine, }) // Get request to render index page app.Get("/", func(c *fiber.Ctx) error { // Render index template return c.Render("index", nil, "layouts/main") }) // Start server log.Fatal(app.Listen(":3000")) } This is a simple server setup with gofiber. We are using html template engine to render the html. ...

Razor Pages + HTMX - Handling form submissions.

Htmx allows us to handle async form submissions with ease by using hx-post attribute. In background it will issue a post request to the url specified in hx-post attribute and replace the element with the response. In this post we will try to handle form submissions in razor pages using htmx. Initialize a new razor pages project. dotnet new razor -o htmx-form In Pages/Index.cshtml we setup the layout. @page @using Htmx @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="row pb-5"> <div class="col"> Form here </div> <div class="col"> Login here </div> </div> Create a partial userform which will be used here and in the post request. ...

HTMX - Handling form submissions.

Htmx allows us to handle async form submissions with ease by using hx-post attribute. In background it will issue a post request to the url specified in hx-post attribute and replace the element with the response. Setup with Gofiber Initialize go module and install dependencies go mod init htmx-form go get github.com/gofiber/fiber/v2 go get github.com/gofiber/template/html/v2 Setup Server package main import ( "log" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/log" "github.com/gofiber/template/html/v2" ) func main() { // Setup html template engine engine := html.New("./views", ".html") app := fiber.New(fiber.Config{ Views: engine, }) // Get request to render index page app.Get("/", func(c *fiber.Ctx) error { values := fiber.Map{ "EmailErr": "", "PasswordErr": "", "Success": "", "Error": "", } // Render index template return c.Render("index", values) }) // Post request to handle form submission app.Post("/form", func(c *fiber.Ctx) error { // Get form values email := c.FormValue("email") password := c.FormValue("password") // Setup values to be passed to template values := fiber.Map{ "EmailValue": email, "EmailErr": "", "PasswordErr": "", "Success": "", "Error": "", } // Validate form values if email == "" { values["EmailErr"] = "Email is required" } if password == "" { values["PasswordErr"] = "Password is required" } if email != "" && password != "" { values["EmailValue"] = "" values["Success"] = "Validation success" } else { values["Error"] = "Validation error" } // Render index template return c.Render("form", values) }) log.Fatal(app.Listen(":3000")) } Setup Views ...

Nextjs - Setup with Bootstrap

Setup nextjs with bootstrap Initialize nextjs project with typescript pnpm create next-app --typescript Install bootstrap pnpm add bootstrap Add bootstrap css to app/layout.tsx or pages/_app import "bootstrap/dist/css/bootstrap.min.css"; Create a bootstrap client component components/Bootstrap.tsx "use client"; import { useEffect } from "react"; function BootstrapClient() { useEffect(() => { require("bootstrap/dist/js/bootstrap.bundle.min.js"); }, []); return null; } export default BootstrapClient; Add bootstrap client component to app/layout.tsx or pages/_app layout.tsx might look like this. import BootstrapClient from "@/components/boostrap"; import "bootstrap/dist/css/bootstrap.css"; import type { Metadata } from "next"; export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body>{children}</body> <BootstrapClient /> </html> ); } Exporting as static site. Add the following to next.config.js ...

Benchmarking JSON vs HTML processing functions

This benchmark compares performance of JSON serialization and HTML template rendering. In a server returning HTML or JSON the main difference is with the serialization. So I wanted to know how much difference it makes to return a JSON response vs HTML response. So I just tested json serialization vs html template rendering in Go. Benchmarking Setup The setup is simple, with go test, main_test.go package main import ( "bytes" "encoding/json" "testing" "text/template" "github.com/flosch/pongo2/v6" ) // Example struct to marshal type SimpleStruct struct { Field1 string `json:"field1"` Field2 int `json:"field2"` } // BenchmarkJsonMarshalling tests the performance of JSON marshaling. func BenchmarkJsonMarshalling(b *testing.B) { // setup any necessary data for the benchmark data := SimpleStruct{ Field1: "example", Field2: 123, } // Run the benchmark for i := 0; i < b.N; i++ { _, err := json.Marshal(data) if err != nil { b.Fatal(err) } } } func BenchmarkHTMLRenderingWithPongo(b *testing.B) { tpl, err := pongo2.FromString("Hello {{ name }}!") if err != nil { panic(err) } // Run the benchmark for i := 0; i < b.N; i++ { _, err := tpl.Execute(pongo2.Context{"name": "florian"}) if err != nil { b.Fatal(err) } } } func BenchmarkHTMLRenderingWithTemplate(b *testing.B) { data := map[string]string{ "Field1": "example", } tmpl := template.Must(template.New("test").Parse("Hello {{ .Field1 }}!")) // Run the benchmark for i := 0; i < b.N; i++ { memory := new(bytes.Buffer) err := tmpl.Execute(memory, data) if err != nil { b.Fatal(err) } } } Benchmarking Results BenchmarkJsonMarshalling-14 9746420 103.6 ns/op BenchmarkHTMLRenderingWithPongo-14 2557006 467.0 ns/op BenchmarkHTMLRenderingWithTemplate-14 7220666 168.7 ns/op My Thoughts JSON serialization is bit faster than HTML template rendering. ...

HTMX - Using hx-select and hx-select-oob

hx-select When the server returns a broad html response, we can use hx-select to select a part of the response and replace the target element with it. For example, consider the following html <body> <div id="main-info"> </div> <div> Some content here </div> <button hx-get="/get-update" hx-target="#main-info" hx-select="#main-info"> update </button> </body> and we get a response from /get-update endpoint like this <div id="main-info"> Main information <p>This is main info</p> </div> <div id="extra-info"> <p>Additional info 1</p> <p>Additional info 2</p> </div> The hx-select will only select the element with id main-info and replace the target element #main-info with it. so the result will be ...

Nextjs - Export as static site

Nextjs is a great framework to create multiple page react applications. It can also export the whole app as a static site. This is extremely useful if we want to avoid nodejs server and use another server like nginx to host the site, which is faster and more efficient. To export the site, we need to change the next.config.js file to include the following: const nextConfig = { distDir: "build", output: "export", }; export default nextConfig; This will export the app as a static site to build folder. The build folder will contain all the static files, which can be hosted using any static hosting solution. ...

HTMX - Using hx-swap-oob

When starting to try htmx, It felt nice that we can interact and replace one area with response. As I started to build something practical, the need for updating multiple elements on response increased. Htmx has an attribute hx-swap-oob which helps to achieve exactly this. (OOB - out of bound) For an html section like this <body> <div id="main-info"> </div> <div> Some content here </div> <div id="extra-info"> </div> <button hx-get="/get-update" hx-target="#main-info" hx-swap="outerHTML"> update </button> </body> On clicking update I want 2 elements #main-info and #extra-info to be updated. Also, in some cases #extra-info can be absent. You can achieve this in one simple step ...