{"id":13878194,"url":"https://github.com/bkuhlmann/htmx","last_synced_at":"2025-04-14T06:21:58.623Z","repository":{"id":167714967,"uuid":"643345481","full_name":"bkuhlmann/htmx","owner":"bkuhlmann","description":"An augmenter and companion to the HTMX JavaScript library.","archived":false,"fork":false,"pushed_at":"2025-03-25T02:10:56.000Z","size":141,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-13T09:49:11.548Z","etag":null,"topics":["htmx","hypermedia","rest","ruby"],"latest_commit_sha":null,"homepage":"https://alchemists.io/projects/htmx","language":"Ruby","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/bkuhlmann.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.adoc","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["bkuhlmann"]}},"created_at":"2023-05-20T21:33:24.000Z","updated_at":"2025-04-09T10:25:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"6b86e932-e22d-4697-961f-0b48b57d9607","html_url":"https://github.com/bkuhlmann/htmx","commit_stats":null,"previous_names":["bkuhlmann/htmx"],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkuhlmann%2Fhtmx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkuhlmann%2Fhtmx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkuhlmann%2Fhtmx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkuhlmann%2Fhtmx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bkuhlmann","download_url":"https://codeload.github.com/bkuhlmann/htmx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248695317,"owners_count":21146952,"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":["htmx","hypermedia","rest","ruby"],"created_at":"2024-08-06T08:01:42.410Z","updated_at":"2025-04-14T06:21:58.582Z","avatar_url":"https://github.com/bkuhlmann.png","language":"Ruby","readme":":toc: macro\n:toclevels: 5\n:figure-caption!:\n\n:htmx_link: link:https://htmx.org[HTMX]\n:hypermedia_systems_link: link:https://hypermedia.systems[Hypermedia Systems]\n:hanami_link: link:https://hanamirb.org[Hanami]\n:roda_link: link:http://roda.jeremyevans.net[Roda]\n:data_link: link:https://alchemists.io/articles/ruby_data[Data]\n:hanamismith_link: link:https://alchemists.io/projects/hanamismith[Hanamismith]\n\n= HTMX\n\nA haiku from the {htmx_link} team:\n\n....\njavascript fatigue:\nlonging for a hypertext\nalready in hand\n....\n\n...and from {hypermedia_systems_link}:\n\n____\nThe goal of [HTMX] is not less JavaScript, but less code, more readable and hypermedia-friendly code.\n____\n\n\nThis gem provides native Ruby support for the {htmx_link} JavaScript library so you can build sophisticated web applications using pure Hypermedia REST APIs while avoiding unnecessary bloat and complexity common with the JavaScript ecosystem. By building upon the original foundations of Hypermedia REST APIs, you can build rich web applications with no additional JavaScript!\n\nAt the moment, the functionality of this gem is still in the early stages of development but the goal of this gem is to aid with the development of {htmx_link} applications.\n\n💡 This is used with the {hanamismith_link} gem when building {hanami_link} applications. Even better, you can play with the link:https://github.com/bkuhlmann/hemo[Hanami demo application] to learn more. Enjoy!\n\ntoc::[]\n\n== Features\n\n- Augments the {htmx_link} JavaScript library.\n- Speeds up {htmx_link} development.\n- Compatible with {hanami_link}, {roda_link}, and other web frameworks.\n\n== Requirements\n\n. A strong understanding of {hypermedia_systems_link}.\n. {htmx_link}.\n. link:https://www.ruby-lang.org[Ruby].\n\n== Setup\n\nTo install _with_ security, run:\n\n[source,bash]\n----\n# 💡 Skip this line if you already have the public certificate installed.\ngem cert --add \u003c(curl --compressed --location https://alchemists.io/gems.pem)\ngem install htmx --trust-policy HighSecurity\n----\n\nTo install _without_ security, run:\n\n[source,bash]\n----\ngem install htmx\n----\n\nYou can also add the gem directly to your project:\n\n[source,bash]\n----\nbundle add htmx\n----\n\nOnce the gem is installed, you only need to require it:\n\n[source,ruby]\n----\nrequire \"htmx\"\n----\n\n== Usage\n\nOne of the first tasks you'll want to tackle, when working with the {htmx_link} library, is building HTMX specific HTML attributes. This can be accomplished by using the `.[]` method. For example, when implementing a {hanami_link} view part, you could use the following:\n\n[source,ruby]\n----\ntag.button(\n  \"Delete\",\n  class: \"button decline\",\n  type: \"submit\",\n  **HTMX[target: \"closest .task\", delete: \"/tasks/#{value.id}\"]\n)\n----\n\nThe above would produce the following:\n\n[source,html]\n----\n\u003cbutton class=\"button decline\" type=\"submit\" hx-target=\"closest .task\" hx-delete=\"/tasks/1\"\u003e\n  Delete\n\u003c/button\u003e\n----\n\nNotice the appropriate HTMX `hx-target` and `hx-delete` attributes are built which are compatible with the {htmx_link} library while not having to manually prefix each one of these attributes with the `hx-` prefix. You can even use symbols, strings, or a mix of both as well.\n\n=== HTML Attribute Prefixes\n\nAs shown above, building HTMX attributes takes minimal effort but if you'd prefer the HTML `data-` prefix, which the {htmx_link} library supports, you can customize by using the following:\n\n[source,ruby]\n----\nprefixer = HTMX::Prefixer.new \"data-hx\"\n\ntag.button(\n  \"Delete\",\n  class: \"button decline\",\n  type: \"submit\",\n  **prefixer.call(target: \"closest .task\", delete: \"/tasks/#{value.id}\")\n)\n----\n\nThis would then produce the following HTML code:\n\n[source,html]\n----\n\u003cbutton class=\"button decline\"\n        type=\"submit\"\n        data-hx-target=\"closest .task\"\n        data-hx-delete=\"/tasks/1\"\n\u003e\n  Delete\n\u003c/button\u003e\n----\n\nAs you can see, the `data-hx-target` and `data-hx-delete` keys are used. These are definitely more verbose than the `hx-` keys. By the way, the `HTMX::Prefixer` is called when using the HTMX `.[]` as shown earlier. This means the following are equivalent:\n\n[source,ruby]\n----\nHTMX[delete: \"/tasks/1\"]\nHTMX::Prefixer.new.call delete: \"/tasks/1\"\nHTMX::Prefixer.new(\"hx\").call delete: \"/tasks/1\"\n----\n\nAll three of the above will produce the same output which means you'll most likely want to use the `.[]` method since it has the shortest syntax.\n\nIf you attempt to use an unsupported prefix, you'll get an error:\n\n[source,ruby]\n----\nHTMX::Prefixer.new \"bogus\"\n# Invalid prefix: \"bogus\". Use: \"hx\" or \"data-hx\". (HTMX::Error)\n----\n\nSome {htmx_link} attributes use dashes. For those situations, you can use strings for keys or underscored symbols to produce the correct HTMX syntax. Here's and example using both a string and symbol for keys:\n\n[source,ruby]\n----\nHTMX[\"swap-oob\" =\u003e true, push_url: \"/demo/123\"]\n# {\"hx-swap-oob\"=\u003etrue, \"hx-push-url\"=\u003e\"/demo/123\"}\n----\n\n=== HTTP Headers\n\nWhen working with HTTP requests/responses, especially HTTP headers, there are a few objects that can parse and make the data easier to work with. These objects are named accordingly: request and response. Here's how to use them.\n\n==== Request\n\nThe request object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#request_headers[HTMX HTTP request headers]. Example:\n\n[source,ruby]\n----\nHTMX::Headers::Request.new\n\n# \u003cdata HTMX::Headers::Request boosted=nil,\n#                              current_url=nil,\n#                              history_restore_request=nil,\n#                              prompt=nil,\n#                              request=nil,\n#                              target=nil,\n#                              trigger_name=nil,\n#                              trigger=nil\n# \u003e\n----\n\nNotice you get a {data_link} instance where all members have the `HX-` prefix removed while each value defaults to `nil`. Even better -- and more practical -- is you can ask the request object to parse the incoming HTTP headers directly and give you _exactly_ what you need:\n\n[source,ruby]\n----\nHTMX::Headers::Request.for request.env\n\n# \u003cdata HTMX::Headers::Request boosted=\"true\",\n#                              current_url=\"/demo\",\n#                              history_restore_request=nil,\n#                              prompt=\"Yes\",\n#                              request=\"true\",\n#                              target=\"demo\",\n#                              trigger_name=\"save\",\n#                              trigger=\"demo\"\n# \u003e\n----\n\nWith the above, the `.for` method plucks out only the HTMX specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.\n\n==== Response\n\nThe response object allows you to obtain a {data_link} object to interact with when parsing link:https://htmx.org/reference/#response_headers[HTMX HTTP response headers]. Example:\n\n[source,ruby]\n----\nHTMX::Headers::Response.new\n\n# \u003cdata HTMX::Headers::Response location=nil,\n#                               push_url=nil,\n#                               redirect=nil,\n#                               refresh=nil,\n#                               replace_url=nil,\n#                               reswap=nil,\n#                               retarget=nil,\n#                               trigger=nil,\n#                               trigger_after_settle=nil,\n#                               trigger_after_swap=nil\n# \u003e\n----\n\nNotice you get a {data_link} instance where all members have the `HX-` prefix removed while each value defaults to `nil`. Even better -- and more practical -- is you can ask the response object to parse the incoming HTTP headers directly and give you _exactly_ what you need:\n\n[source,ruby]\n----\nHTMX::Headers::Response.for response.headers\n\n# \u003cdata HTMX::Headers::Response location=\"/\",\n#                               push_url=\"/demo\",\n#                               redirect=\"/demo\",\n#                               refresh=\"true\",\n#                               replace_url=\"/demo\",\n#                               reswap=\"none\",\n#                               retarget=\".demo\",\n#                               trigger=\"demo\",\n#                               trigger_after_settle=\"demo\",\n#                               trigger_after_swap=\"demo\"\n# \u003e\n----\n\nWith the above, the `.for` method plucks out only the HTMX specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.\n\n=== Errors\n\nAs you've probably picked up by now, any/all errors issued by this gem will be an instance of the `HTMX::Error` class which inherits from `StandardError`. you can use this classification to catch and deal with these errors in your own implementation as desired.\n\n== Development\n\nTo contribute, run:\n\n[source,bash]\n----\ngit clone https://github.com/bkuhlmann/htmx\ncd htmx\nbin/setup\n----\n\nYou can also use the IRB console for direct access to all objects:\n\n[source,bash]\n----\nbin/console\n----\n\n== Tests\n\nTo test, run:\n\n[source,bash]\n----\nbin/rake\n----\n\n== link:https://alchemists.io/policies/license[License]\n\n== link:https://alchemists.io/policies/security[Security]\n\n== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]\n\n== link:https://alchemists.io/policies/contributions[Contributions]\n\n== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]\n\n== link:https://alchemists.io/projects/htmx/versions[Versions]\n\n== link:https://alchemists.io/community[Community]\n\n== Credits\n\n* Built with link:https://alchemists.io/projects/gemsmith[Gemsmith].\n* Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].\n","funding_links":["https://github.com/sponsors/bkuhlmann"],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkuhlmann%2Fhtmx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbkuhlmann%2Fhtmx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkuhlmann%2Fhtmx/lists"}