htmx

An augmenter and companion to the HTMX JavaScript library.

https://github.com/bkuhlmann/htmx

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (10.9%) to scientific vocabulary

Keywords

htmx hypermedia rest ruby
Last synced: 4 months ago · JSON representation ·

Repository

An augmenter and companion to the HTMX JavaScript library.

Basic Info
Statistics
  • Stars: 16
  • Watchers: 3
  • Forks: 0
  • Open Issues: 0
  • Releases: 0
Topics
htmx hypermedia rest ruby
Created over 2 years ago · Last pushed 4 months ago
Metadata Files
Readme Funding License Citation

README.adoc

:toc: macro
:toclevels: 5
:figure-caption!:

:htmx_link: link:https://htmx.org[htmx]
:hypermedia_systems_link: link:https://hypermedia.systems[Hypermedia Systems]
:hanami_link: link:https://hanamirb.org[Hanami]
:roda_link: link:http://roda.jeremyevans.net[Roda]
:data_link: link:https://alchemists.io/articles/ruby_data[Data]
:hanamismith_link: link:https://alchemists.io/projects/hanamismith[Hanamismith]

= HTMX

A haiku from the {htmx_link} team:

....
javascript fatigue:
longing for a hypertext
already in hand
....

...and from {hypermedia_systems_link}:

____
The goal of [htmx] is not less JavaScript, but less code, more readable and hypermedia-friendly code.
____


This 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!

💡 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!

toc::[]

== Features

- Augments the {htmx_link} JavaScript library.
- Speeds up {htmx_link} development.
- Compatible with {hanami_link}, {roda_link}, and other web frameworks.

== Requirements

. A strong understanding of {hypermedia_systems_link}.
. {htmx_link}.
. link:https://www.ruby-lang.org[Ruby].

== Setup

To install _with_ security, run:

[source,bash]
----
# 💡 Skip this line if you already have the public certificate installed.
gem cert --add <(curl --compressed --location https://alchemists.io/gems.pem)
gem install htmx --trust-policy HighSecurity
----

To install _without_ security, run:

[source,bash]
----
gem install htmx
----

You can also add the gem directly to your project:

[source,bash]
----
bundle add htmx
----

Once the gem is installed, you only need to require it:

[source,ruby]
----
require "htmx"
----

== Usage

One 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:

[source,ruby]
----
tag.button(
  "Delete",
  class: "button decline",
  type: "submit",
  **HTMX[target: "closest .task", delete: "/tasks/#{value.id}"]
)
----

The above would produce the following:

[source,html]
----

----

Notice 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 use symbols, strings, or a mix of both as well.

=== HTML Attribute Prefixes

As 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:

[source,ruby]
----
prefixer = HTMX::Prefixer.new "data-hx"

tag.button(
  "Delete",
  class: "button decline",
  type: "submit",
  **prefixer.call(target: "closest .task", delete: "/tasks/#{value.id}")
)
----

This would then produce the following HTML code:

[source,html]
----

----

As 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:

[source,ruby]
----
HTMX[delete: "/tasks/1"]
HTMX::Prefixer.new.call delete: "/tasks/1"
HTMX::Prefixer.new("hx").call delete: "/tasks/1"
----

All 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.

If you attempt to use an unsupported prefix, you'll get an error:

[source,ruby]
----
HTMX::Prefixer.new "bogus"
# Invalid prefix: "bogus". Use: "hx" or "data-hx". (HTMX::Error)
----

Some {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 an example using both a string and symbol for keys:

[source,ruby]
----
HTMX["swap-oob" => true, push_url: "/demo/123"]
# {"hx-swap-oob"=>true, "hx-push-url"=>"/demo/123"}
----

=== HTTP Headers

When working with HTTP requests/responses, especially HTTP headers, there are a couple of methods that can parse and make the data easier to work with. Here's how to use them.

==== Requests

The 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:

[source,ruby]
----
HTMX.request

# 
----

Notice 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:

[source,ruby]
----
HTMX.request "HTTP_HX_BOOSTED" => "true",
             "HTTP_HX_CURRENT_URL" => "/demo",
             "HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
             "HTTP_HX_PROMPT" => "Yes",
             "HTTP_HX_REQUEST" => "true",
             "HTTP_HX_TARGET" => "demo",
             "HTTP_HX_TRIGGER_NAME" => "save",
             "HTTP_HX_TRIGGER" => "demo"

# 
----

As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.

As an added convenience, you can use predicate methods for boolean values. Example:

[source,ruby]
----
headers = HTMX.request "HTTP_HX_BOOSTED" => "true",
                       "HTTP_HX_CURRENT_URL" => "/demo",
                       "HTTP_HX_HISTORY_RESTORE_REQUEST" => "false",
                       "HTTP_HX_PROMPT" => "Yes",
                       "HTTP_HX_REQUEST" => "true",
                       "HTTP_HX_TARGET" => "demo",
                       "HTTP_HX_TRIGGER_NAME" => "save",
                       "HTTP_HX_TRIGGER" => "demo"

headers.boosted?                  # true
headers.confirmed?                # true
headers.history_restore_request?  # false
headers.request?                  # true
----

Use of `#confirmed?` is the only unique predicate method since it answers a boolean based on the truthiness of the `HTTP_HX_PROMPT` header. For further details, see `String#truthy?` as provided by the link:https://alchemists.io/projects/refinements#_truthy[Refinements] gem.

Due to `HTML.request` delegating to the `HTMX::Headers::Request`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:

[source,ruby]
----
HTMX::Headers::Request.for(**headers)                 # Identical to `HTMX.request`.
HTMX::Headers::Request.key_for "HTTP_HX_CURRENT_URL"  # :current_url
HTMX::Headers::Request.header_for :current_url        # "HTTP_HX_CURRENT_URL"
----

Should you not want to use `HTMX::Headers::Request`, you can use the request predicate methods instead. Example:

[source,ruby]
----
headers = {}

HTMX.request! headers, boosted: true, prompt: "Yes"
# {"HTTP_HX_BOOSTED" => true, "HTTP_HX_PROMPT" => "Yes"}

HTMX.request? headers, :prompt, "Yes"  # true
HTMX.request? headers, :prompt, "On"   # false
----

💡 `HTMX.request!` is designed to mutate your original headers. Unknown attributes are merged as is.

==== Responses

The 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:

[source,ruby]
----
HTMX.response

# 
----

Notice 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:

[source,ruby]
----
HTMX.response "HX-Location" => "/",
              "HX-Push-Url" => "/demo",
              "HX-Redirect" => "/demo",
              "HX-Refresh" => "true",
              "HX-Replace-Url" => "/demo",
              "HX-Reswap" => "none",
              "HX-Retarget" => ".demo",
              "HX-Trigger" => "demo",
              "HX-Trigger-After-Settle" => "demo",
              "HX-Trigger-After-Swap" => "demo"

# 
----

As you can see, this method only plucks out the htmx specific headers which may or may not have values. Extra header keys, which are not specific to {htmx_link}, are ignored.

There is also a refresh predicate method that'll answer a boolean for convenience. Example:

[source,ruby]
----
headers = HTMX.response "HX-Refresh" => "true"

headers.refresh? # true
----

Due to `HTML.response` delegating to the `HTMX::Headers::Response`, this means you can use the object directly. Specifically, you can obtain the record, key, or header depending on your needs. Example:

[source,ruby]
----
HTMX::Headers::Response.for(**headers)         # Identical to `HTMX.response`.
HTMX::Headers::Response.key_for "HX-Location"  # :location
HTMX::Headers::Response.header_for :location   # "HX-Location"
----

Should you not want to use `HTMX::Headers::Response`, you can use the response predicate methods instead. Example:

[source,ruby]
----
headers = {}

HTMX.response! headers, location: "/", push_url: "/test"
# {"HX-Location" => "/", "HX-Push-Url" => "/test"}

HTMX.response? headers, :push_url, "/test"   # true
HTMX.response? headers, :push_url, "/other"  # false
----

💡 `HTMX.response!` is designed to mutate your original headers. Unknown attributes are merged as is.

=== Errors

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.

== Development

To contribute, run:

[source,bash]
----
git clone https://github.com/bkuhlmann/htmx
cd htmx
bin/setup
----

You can also use the IRB console for direct access to all objects:

[source,bash]
----
bin/console
----

== Tests

To test, run:

[source,bash]
----
bin/rake
----

== link:https://alchemists.io/policies/license[License]

== link:https://alchemists.io/policies/security[Security]

== link:https://alchemists.io/policies/code_of_conduct[Code of Conduct]

== link:https://alchemists.io/policies/contributions[Contributions]

== link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin]

== link:https://alchemists.io/projects/htmx/versions[Versions]

== link:https://alchemists.io/community[Community]

== Credits

* Built with link:https://alchemists.io/projects/gemsmith[Gemsmith].
* Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].

Owner

  • Name: Brooke Kuhlmann
  • Login: bkuhlmann
  • Kind: user
  • Location: Boulder, CO USA
  • Company: Alchemists

Quality over quantity.

Citation (CITATION.cff)

cff-version: 1.2.0
message: Please use the following metadata when citing this project in your work.
title: HTMX
abstract: An augmenter and companion to the HTMX JavaScript library.
version: 2.4.0
license: Hippocratic-2.1
date-released: 2025-08-01
authors:
  - family-names: Kuhlmann
    given-names: Brooke
    affiliation: Alchemists
    orcid: https://orcid.org/0000-0002-5810-6268
keywords:
 - ruby
 - htmx
 - rest
 - hypermedia
repository-code: https://github.com/bkuhlmann/htmx
repository-artifact: https://rubygems.org/gems/htmx
url: https://alchemists.io/projects/htmx

GitHub Events

Total
  • Watch event: 1
  • Delete event: 38
  • Push event: 38
  • Create event: 8
Last Year
  • Watch event: 1
  • Delete event: 38
  • Push event: 38
  • Create event: 8

Issues and Pull Requests

Last synced: 4 months ago

All Time
  • Total issues: 0
  • Total pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Total issue authors: 0
  • Total pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
Pull Request Authors
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • rubygems 11,560 total
  • Total dependent packages: 1
  • Total dependent repositories: 1
  • Total versions: 24
  • Total maintainers: 1
rubygems.org: htmx

An augmenter and companion to the HTMX JavaScript library.

  • Versions: 24
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 11,560 Total
Rankings
Dependent packages count: 7.7%
Stargazers count: 15.1%
Dependent repos count: 21.7%
Forks count: 31.6%
Average: 34.1%
Downloads: 94.3%
Maintainers (1)
Funding
  • https://github.com/sponsors/bkuhlmann
Last synced: 4 months ago