Skip to content

pickleprat/htmx-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

htmx-go

GoDoc License Issues Stars

A type-safe library for working with HTMX in Go.

Less time fiddling with HTTP headers, more time developing awesome Hypermedia-driven applications.

Easily check if requests are from HTMX, and utilize a type-safe, declarative syntax for HTMX response headers to control HTMX behavior from the server.

Uses standard net/http types. Has some integration with templ components.

import (
  "net/http"
  "github.com/angelofallars/htmx-go"
)

func(w http.ResponseWriter, r *http.Request) {
	if htmx.IsHTMX(r) {
		htmx.NewResponse().
			Reswap(htmx.SwapBeforeEnd).
			Retarget("#errors").
			ReplaceURL("/errors").
			Write(w)
	}
}

Installation

Use go get.

go get github.com/angelofallars/htmx-go

Then import htmx-go:

import "github.com/angelofallars/htmx-go"

HTMX requests

Check request origin

You can determine if a request is from HTMX. With this, you can add custom handling for non-HTMX requests.

You can also use this for checking if this is a GET request for the initial (very first) page loads on your website, as initial page load requests don't use HTMX.

func(w http.ResponseWriter, r *http.Request) {
	if htmx.IsHTMX(r) {
		// logic for handling HTMX requests
	} else {
		// logic for handling non-HTMX requests (e.g. render a full page for first-time visitors)
	}
}

Check if request is Boosted (hx-boost)

func(w http.ResponseWriter, r *http.Request) {
	if htmx.IsBoosted(r) {
		// logic for handling boosted requests
	} else {
		// logic for handling non-boosted requests
	}
}

HTMX responses

htmx-go takes inspiration from Lip Gloss for a declarative way of specifying HTMX response headers.

Basic usage

Make a response writer with htmx.NewResponse(), and add a header to it to make the page refresh:

func(w http.ResponseWriter, r *http.Request) {
 	writer := htmx.NewResponse().Refresh(true)
 	writer.Write(w)
}

Retarget response to a different element

func(w http.ResponseWriter, r *http.Request) {
	htmx.NewResponse().
		// Override 'hx-target' to specify which target to load into
		Retarget("#errors").
		// Also override the 'hx-swap' value of the request
		Reswap(htmx.SwapBeforeEnd).
		Write(w)
}

Triggers

You can add triggers and let htmx-go take care of formatting and JSON serialization of the header values.

Define event triggers:

  • htmx.Trigger(eventName string) - A trigger with no details.
  • htmx.TriggerDetail(eventName string, detailValue string) - A trigger with one detail value.
  • htmx.TriggerObject(eventName string, detailObject any) - A trigger with a JSON-serializable detail object. Recommended to pass in either map[string]string or structs with JSON field tags.

Set trigger headers using the triggers above:

  • Response.AddTrigger(trigger ..EventTrigger) - appends to the HX-Trigger header
  • Response.AddTriggerAfterSettle(trigger ..EventTrigger) - appends to the HX-Trigger-After-Settle header
  • Response.AddTriggerAfterSwap(trigger ..EventTrigger) - appends to the HX-Trigger-After-Swap header
htmx.NewResponse().
	AddTrigger(htmx.Trigger("myEvent"))
// HX-Trigger: myEvent

htmx.NewResponse().
	AddTrigger(htmx.TriggerDetail("showMessage", "Here Is A Message"))
// HX-Trigger: {"showMessage":"Here Is A Message"}

htmx.NewResponse().
	AddTrigger(
			htmx.TriggerDetail("hello", "world"),
			htmx.TriggerObject("myEvent", map[string]string{
				"level":   "info",
				"message": "Here Is A Message",
			}),
  )
// HX-Trigger: {"hello":"world","myEvent":{"level":"info","message":"Here is a Message"}}

Code organization

HTMX response writers can be declared outside of functions with var so you can reuse them in several places.

Caution

If you're adding additional headers to a global response writer, always use the .Clone() method to avoid accidentally modifying the global response writer.

var deleter = htmx.NewResponse().
    Reswap(htmx.SwapDelete)

func(w http.ResponseWriter, r *http.Request) {
	deleter.Clone().
		Reselect("#messages").
		Write(w)
}

Templ integration

HTMX pairs well with Templ, and this library is no exception. You can render both the necessary HTMX response headers and Templ components in one step with the .RenderTempl() method.

// hello.templ
templ Hello() {
    <div>Hello { name }!</div>
}

// main.go
func(w http.ResponseWriter, r *http.Request) {
	htmx.NewResponse().
		Retarget("#hello").
		RenderTempl(r.Context(), w, Hello())
}

Note

To avoid issues with custom HTTP status code headers with this approach, it is recommended to use Response().StatusCode() so the status code header is always set after the HTMX headers.

Stop polling

If you have an element that is polling a URL and you want it to stop, use the htmx.StatusStopPolling 286 status code in a response to cancel the polling. HTMX documentation reference

w.WriteHeader(htmx.StatusStopPolling)

Header names

If you need to work with HTMX headers directly, htmx-go provides constant values for all HTTP header field names of HTMX so you don't have to write them yourself. This mitigates the risk of writing header names with typos.

// Request headers
const (
	HeaderBoosted               = "HX-Boosted"
	HeaderCurrentURL            = "HX-Current-URL"
	HeaderHistoryRestoreRequest = "HX-History-Restore-Request"
	HeaderPrompt                = "HX-Prompt"
	HeaderRequest               = "Hx-Request"
	HeaderTarget                = "HX-Target"
	HeaderTriggerName           = "Hx-Trigger-Name"
)

// Common headers
const (
	HeaderTrigger = "HX-Trigger"
)

// Response headers
const (
	HeaderLocation           = "HX-Location"
	HeaderPushURL            = "HX-Push-Url"
	HeaderRedirect           = "HX-Redirect"
	HeaderRefresh            = "HX-Refresh"
	HeaderReplaceUrl         = "HX-Replace-Url"
	HeaderReswap             = "HX-Reswap"
	HeaderRetarget           = "HX-Retarget"
	HeaderReselect           = "HX-Reselect"
	HeaderTriggerAfterSettle = "HX-Trigger-After-Settle"
	HeaderTriggerAfterSwap   = "HX-Trigger-After-Swap"
)

Compatibility

This library is compatible with the standard net/http library, as well as other routers like Chi and Gorilla Mux that use the standard http.HandlerFunc handler type.

With the Echo web framework, try passing in context.Request() and context.Response().Writer for requests and responses, respectively.

With the Gin web framework on the other hand, try using context.Request and context.Writer.

Additional resources

Contributing

Pull requests are welcome!

License

MIT

About

</> Build awesome HTMX + Go projects faster.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 100.0%