{"id":22362691,"url":"https://github.com/will-wow/typed-htmx-go","last_synced_at":"2025-07-30T14:32:46.851Z","repository":{"id":223628612,"uuid":"760392132","full_name":"will-wow/typed-htmx-go","owner":"will-wow","description":"Well-documented Go functions for building HTMX attributes.","archived":false,"fork":false,"pushed_at":"2024-05-27T17:27:49.000Z","size":319,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-06-22T00:22:41.561Z","etag":null,"topics":["golang","htmx","templ"],"latest_commit_sha":null,"homepage":"https://thxgo.willwow.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/will-wow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-20T10:35:00.000Z","updated_at":"2024-06-20T14:22:47.000Z","dependencies_parsed_at":"2024-05-27T19:48:43.116Z","dependency_job_id":"242a8c25-6b86-442d-92ba-a2677707d437","html_url":"https://github.com/will-wow/typed-htmx-go","commit_stats":null,"previous_names":["will-wow/typed-htmx-go"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will-wow%2Ftyped-htmx-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will-wow%2Ftyped-htmx-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will-wow%2Ftyped-htmx-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will-wow%2Ftyped-htmx-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/will-wow","download_url":"https://codeload.github.com/will-wow/typed-htmx-go/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228154026,"owners_count":17877704,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","htmx","templ"],"created_at":"2024-12-04T17:10:25.367Z","updated_at":"2024-12-04T17:10:26.548Z","avatar_url":"https://github.com/will-wow.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typed-htmx-go/hx\n\nWell-documented Go functions for building [HTMX](https://htmx.org) attributes.\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/will-wow/typed-htmx-go.svg)](https://pkg.go.dev/github.com/will-wow/typed-htmx-go/htmx)\n![Code Coverage](./assets/badge.svg)\n\n[htmx](https://htmx.org) is a powerful and simple tool for building dynamic, server-rendered web applications. It also pairs particularly well with [Templ](https://templ.guide) (a JSX-like template language for Go) and [Gomponents](https://www.gomponents.com/) (a Go-native view library).\n\nHowever, when using it I have to have the [docs](https://htmx.org/reference) open, to look up the specifics of each modifier. I wanted the simplicity of HTMX, the editor support of Go, and beautiful integration with Templ, without sacrificing performance. I built typed-htmx-go.\n\n`hx.NewTempl()` provides an `hx` struct that exposes all documented [HTMX attributes](https://htmx.org/reference/) as Go functions, and [templ.Attributes](https://templ.guide/syntax-and-usage/attributes) to be spread into a Templ element. `hx.NewGomponents()` returns an `hx` struct that exposes attributes as functions that return `g.Node` attributes instead.. You can also support other templating libraries by simply passing an `attr` function to `htmx.NewHX(attr)`.\n\nEach function and option includes a Godoc comment copied from the extensive HTMX docs, so you can access that documentation right from the comfort of your editor.\n\n## Installation\n\n```bash\ngo get github.com/will-wow/typed-htmx-go\n```\n\n## Usage\n\n```go\nimport (\n\t\"time\"\n\n\t\"github.com/will-wow/typed-htmx-go/htmx\"\n\t\"github.com/will-wow/typed-htmx-go/htmx/trigger\"\n\t\"github.com/will-wow/typed-htmx-go/htmx/swap\"\n)\n\nvar hx = htmx.NewTempl()\n\ntempl search() {\n\t\u003ch3\u003e\n\t\tSearch Contacts\n\t\t\u003cspan class=\"htmx-indicator\"\u003e\n\t\t\t\u003cimg src=\"/static/img/bars.svg\"/\u003e Searching...\n\t\t\u003c/span\u003e\n\t\u003c/h3\u003e\n\t\u003cinput\n\t\ttype=\"search\"\n\t\tname=\"search\"\n\t\tplaceholder=\"Begin Typing To Search Users...\"\n\t\t{ hx.Post(\"/examples/templ/active-search/search/\")... }\n\t\t{ hx.TriggerExtended(\n\t\t\ttrigger.On(\"input\").Changed().Delay(time.Millisecond * 500),\n\t\t\ttrigger.On(\"search\"),\n\t\t)... }\n\t\t{ hx.Target(\"#search-results\")... }\n\t\t{ hx.Swap(swap.OuterHTML)... }\n\t\t{ hx.Indicator(\".htmx-indicator\")... }\n\t/\u003e\n\t\u003ctable\u003e\n\t\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\u003cth\u003eFirst Name\u003c/th\u003e\n\t\t\t\t\u003cth\u003eLast Name\u003c/th\u003e\n\t\t\t\t\u003cth\u003eEmail\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\u003c/thead\u003e\n\t\t\u003ctbody id=\"search-results\"\u003e\u003c/tbody\u003e\n\t\u003c/table\u003e\n}\n```\n\n## Extensions\n\nhtmx includes a set of extensions out of the box that address common developer needs. These extensions are tested against htmx in each distribution.\n\nWhile you can always use any extension by adding standard HTML attributes, `typed-htmx-go` has typed support for some extensions.\n\nThese extensions each have their own package, and expose function that take a configured `hx` as a first parameter, and return a full attribute.\n\n`hx` also includes an `hx.Ext()` method to register an extension on an element (ie: `{ hx.Ext(classtools.Extension)... }` instead of `hx-ext=\"class-tools\"`).\n\n### Example\n\n```go\nvar hx = htmx.NewTempl()\n\n\u003chead\u003e\n\t\u003cscript src=\"https://unpkg.com/htmx.org@1.9.12/dist/ext/class-tools.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n...\n\u003cdiv { hx.Ext(classtools.Extension)... }\u003e\n\t\u003cdiv { classtools.Classes(hx, classtools.Add(\"foo\", time.Millisecond*100))... } /\u003e\n\t\u003cdiv class=\"bar\" { classtools.ClassesParallel(hx, []classtools.Run{\n\t\t\t{classtools.Remove(\"bar\", time.Second)},\n\t\t\t{classtools.Add(\"foo\", time.Second)},\n\t})... } /\u003e\n\u003c/div\u003e\n```\n\n### Current Extensions supported\n\nSome of the more complex extensions supported:\n\n- [`class-tools`](https://pkg.go.dev/github.com/will-wow/typed-htmx-go/htmx/ext/classtools)\n- [`preload`](https://pkg.go.dev/github.com/will-wow/typed-htmx-go/htmx/ext/preload)\n- [`response-targets`](https://pkg.go.dev/github.com/will-wow/typed-htmx-go/htmx/ext/responsetargets)\n- [`loading-states`](https://pkg.go.dev/github.com/will-wow/typed-htmx-go/htmx/ext/loadingstates)\n\nSee [htmx/ext](./htmx/ext) for a full list of extensions.\n\n## Examples\n\nUsage examples are in [examples](./examples) (hosted at [typed-htmx-go.vercel.app](https://typed-htmx-go.vercel.app/))\n\nThese are mostly ported from the [HTMX examples](https://htmx.org/examples/), but include a Templ and Gomponents implementation, and working server code to borrow from.\n\n## HTMX Version\n\n`typed-htmx-go` strives to keep up with HTMX releases. It currently supports HTMX `v1.9.10`.\n\n## Goals\n\nThe project has some specific goals that drive the API.\n\n### Complete HTMX attribute support\n\nEvery documented HTMX attribute and modifier should have a corresponding Go function. If it's missing something please submit an issue or a PR! And in the meantime, you can always drop back to a raw HTML attribute.\n\n### No stringly-typed options\n\nMany HTMX attributes (like `hx-swap` and `hx-trigger`) support a complex syntax of methods, modifiers, and selectors in the attribute string (like `hx-trigger='click[isActive] consume from:(#parent \u003e #child) queue:first target:#element'`).\n\nThat's necessary for a tool that embeds in standard HTML attributes, but it requires a lot of studying the docs to get exactly right.\n\n`hx` strives to provide typed builders that ensure you're passing the right options to the right modifiers.\n\nFor instance, many attributes (like [hx-target](https://htmx.org/attributes/hx-target/) and [hx-include](https://htmx.org/attributes/hx-include/)) support \"extended selectors\", which is either a standard CSS selector, or some non-standard keyword like `this` or `closest`. But different attributes support different non-standard selectors, so they have their own types; `HX.Target()` takes an `htmx.TargetSelector` that supports only `this`, `next`, or `previous`, plus optionally any of the standard relative modifiers like `closest` or `find`, while `HX.Include()` takes an `htmx.IncludeSelector` that only allows the `closest` modifier, and no non-standard selectors. Since they also take any arbitrary CSS selector, you can pass in any string, but sticking to the provided types when available makes it easier to make sure you've got valid selectors.\n\nExample:\n\n```go\nhx.Target(\"#element\")\nhx.Target(htmx.TargetRelative(htmx.Next, \"#element\"))\nhx.Target(htmx.TargetNext)\n\nhx.Include(\"#element\")\nhx.Include(IncludeThis)\nhx.Include(htmx.IncludeRelative(htmx.Next, \"#element\"))\nhx.Include(htmx.TargetNext) // Invalid: cannot use TargetNext (constant \"next\" of type TargetSelector) as IncludeSelector value in argument to hx.Include\n```\n\n### Full documentation in-editor\n\nThe [HTMX References](https://htmx.org/reference/) are through and readable (otherwise this project wouldn't have been possible!) However, having those docs at your fingertips as you write, instead of in a separate tab, is even better.\n\n`hx` strives to have a Go-adjusted copy of every line of documentation from the HTMX References, including examples, included in the godocs of functions and options, and an example test.\n\nNote: Documentation is in progress. If you see something missing, please submit a PR!\n\n### Support many component libraries\n\n`hx` is built to support any Go HTML templating library that can take attributes as some data type. The two supported out of the box are Templ and Gomponents, but it should be easy work with other libraries. And if you do use `typed-htmx-go` with another library, please submit a PR to add official support!\n\nTo handle the different types (Templ expects a `Templ.Attributes map[string]any`, and Gomponents wants a `g.Node` with a `Render` method), the `htmx.NewHX` constructor takes an `attr` function that takes an HTMX attribute and an `any` value, and returns some type T. That means you can construct an `hx` that returns `Templ.Attributes` from every attribute function, one that returns a `g.Node`, and another that returns whatever your library expects.\n\nFor ease of use, you should create a private `var hx` in your template packages, like so:\n\n```go\nvar hx = htmx.NewTempl()\n\ntempl MyDiv() {\n  \u003cbutton { hx.Get(\"/some/path\")... } /\u003e\n}\n```\n\n### Transferable HTMX skills\n\nAs much as possible, it should be the case that if you know HTMX, you can use `hx`, and using `hx` should prepare you to use raw HTMX. That means that attributes functions should match their HTMX counterparts, names should match terms in the docs, and arguments should occur in the order they are printed in the HTML.\n\nThis also means that written `hx` attributes should look like HTMX attributes. So if in HTMX you would write:\n\n```html\n\u003cform\n  method=\"GET\"\n  action=\"/page\"\n  hx-get=\"/page\"\n  hx-target=\"body\"\n  hx-replace-url=\"true\"\n  hx-swap=\"scroll:#search-results:top swap:1s\"\n\u003e\u003c/form\u003e\n```\n\nThe `hx` equivalent should take the same names and values in the same order:\n\n```go\n// templ\n\u003cform\n\tmethod=\"GET\"\n\taction=\"/page\"\n\t{ hx.Get(\"/page\")... }\n\t{ hx.Target(\"body\")... }\n\t{ hx.ReplaceURL(true)... }\n\t{ hx.Swap(\n\t\tswap.New().\n\t\tScrollElement(\"#search-results\", swap.Top).\n\t\tSwap(time.Second),\n\t)... }\n\u003e\n```\n\n```go\n// gomponents\nForm(\n\tMethod(\"GET\"),\n\tAction(\"/page\"),\n\thx.Get(\"/page\"),\n\thx.Target(\"body\"),\n\thx.ReplaceURL(true),\n\thx.Swap(\n\t\tswap.New().\n\t\tScrollElement(\"#search-results\", swap.Top).\n\t\tSwap(time.Second),\n\t),\n)\n```\n\n### Fully tested\n\nEvery attribute function should have a test to make sure it's printing valid HTMX. And every function and option should include an example test, to make it easy to see usage in the godocs. These are also a good opportunity to try out the API and make sure it's ergonomic in practice.\n\n## Contributing\n\n### Install Tasklist\n\n```bash\ngo install github.com/go-task/task/v3/cmd/task@latest\n```\n\n### Install tools\n\n```bash\ntask tools\n```\n\n### Check that everything is ready to commit, and update the coverage badge\n\n```bash\ntask ready\n```\n\n### Publish\n\n```bash\nVERSION=\"0.0.0\" task publish\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill-wow%2Ftyped-htmx-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwill-wow%2Ftyped-htmx-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill-wow%2Ftyped-htmx-go/lists"}