もうjsなんていらない！世界で流行っているHTMXについてまとめてみた

# HTMXとは

<https://htmx.org/>

HTMXは、JavaScript を記述せずに、Ajax通信や高度なUXを実現できるライブラリ。

**軽量** で **高速** で、既存のサーバーサイドのフレームワークとシームレスなやり取りができる。また、AJAX通信の発火、フォームの送信処理、DOMの更新などを既存のHTML要素を拡張するだけで可能とする。[WebSocket](#web-socket)や[SSE](#sse)にも対応しているので、チャットアプリなどにも適している。

[2023 JavaScript Rising Stars](https://risingstars.js.org/2023/en)では、 **フロントエンド・フレームワーク**部門で見事2位に輝いた！(一位はReact、全部門だと[shadcn/ui](https://qiita.com/twrcd1227/items/d4a67bb155503fde30f5))　似たような機能として、Ruby on Railsの[HotWire](https://hotwired.dev/)があるらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/36b132f1-93a9-4fcc-4fef-0a0179b2efe2.png)

2024年はHTMXがくると言われているぐらい世界で騒がれているのだが、あまり日本では流行っていない。以下はGoogleトレンドで調べた結果である。

## アメリカの動向

アメリカやイギリスでは、2023年から **HTMX** がきてる。
全世界を対象にしてもほぼ同じ結果。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/a83727ed-c709-cd67-306b-43acae9e4c9a.png)

## 日本

昔から何も変わっていない。つまり、全然人気ではないということ。
明らかに最先端のアメリカやイギリスと比べると盛り上がりがない。これから盛り上げよう！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/5fe02ca6-933e-a1fd-0826-5c2ad1262b36.png)

# インストール

## CDN

以下の1行をheadに書くだけ。ただ、CDNは本番環境で使うのは非推奨である。

```html
<script src="https://unpkg.com/htmx.org@1.9.10/dist/htmx.js"></script>
```

## ダウンロード

<https://unpkg.com/htmx.org@1.9.10/dist/htmx.min.js> をコピーして、`htmx.min.js`に保存して以下のように読み込む。

```html
<script src="/path/to/htmx.min.js"></script>
```

## npm

```txt
npm install htmx.org
```

## webpack

npmかyarnでインストールする。

`index.js`などのエントリーファイルに以下を追加。

```js
import 'htmx.org';
```

カスタムJSファイルを作成し、エントリーファイルに以下を追加してimportする。

```js
import 'path/to/my_custom.js';
```

カスタムJSファイルに以下を追加して、バンドルをリビルドする。

```js
window.htmx = require('htmx.org');
```

# fakeAPI

今回サーバ側は[JSON Placeholder](https://jsonplaceholder.typicode.com/)というfakeAPIを使用する。このサーバはJSON形式のレスポンスを返す。

| メソッド | URL |
|:-:|:-:|
| GET  | /post/1 |
| POST  | /posts |
| PUT  |  /posts/1 |
| PATCH  | /posts/1 |
| DELETE  | /posts/1 |

また、XML形式のレスポンスを必要とする場合は[TheTestRequest](https://thetestrequest.com/)を使う。

| メソッド | URL |
|:-:|:-:|
| GET  | /authors/1.xml |

:::note
今回はわかりやすくJSONレスポンスを使ってることが多いが、HTMXはDOMをレスポンスで置換するため、HTML形式であることが多い。実際にJSONレスポンスを扱う場合は拡張機能の[client-side-templates](#client-side-templates)を使用する
:::

# Ajax

基本的なAjax通信のやり方を説明する。
GETリクエストの場合、以下のように`hx-get=<url>`属性を追加するだけでいい。

```html
 <div hx-get="/example">Hello</div>
```

GETリクエスト以外も`hx-get`と同じく以下の属性を指定すればできる。

|    属性    |    説明   |
|   :-:   |   :-:  |
| hx-get | GET    |
| hx-post | POST   |
| hx-put | PUT    |
| hx-patch | PATCH  |
| hx-delete | DELETE |

実際にそれぞれの例を以下に示す。以下の例では、clickボタンを押すとajax通信が行われて、ボタンの文字が変わる。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="oNVzLQd" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/oNVzLQd">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# ターゲット

`hx-target`を使うと、ターゲットの要素を指定できる。
リクエストを行った要素以外の別の要素にレスポンスをロードしたい場合に使う。
以下の例では、クリックすると、ボタンの中身が置き換わってしまう。

```html
<p>あいうえお</p>
<button hx-get="https://jsonplaceholder.typicode.com/posts/1" hx-trigger="click">クリック</button>
```

| 拡張CSSセレクタ | 説明 |例|
|:-:|:-:|:-:|
| this  | 自分自身を指定する。デフォルト| hx-target="this"|
| closest \<CSSセレクタ\>  | CSSセレクタに一致する<br>一番近い親を指定する  |　hx-target="closest tr"|
| find \<CSSセレクタ\>  | CSSセレクタに一致する<br>一番近い子を指定する | hx-target="find div" |
| next \<CSSセレクタ\>  | CSSセレクタに一致する<br>DOM 内の次の要素を指定する  | hx-target="next target" |
| previous \<CSSセレクタ\>  | CSSセレクタに一致する<br>前の要素を指定する  | hx-target="previous target" |

`hx-target`だけでなく、CSSセレクタを受け取るほとんどの属性は、上記の拡張CSS構文をサポートしている。CSSセレクタについては[CSSセレクタ](https://www.w3schools.com/cssref/css_selectors.php)を参照。さらに、`< />`で囲み、ハイパースクリプトのクエリリテラル構文を模倣することもできる。(参考 : [query reference](https://hyperscript.org/expressions/query-reference/))

上記の5つの構文についての例を以下に挙げる。クリックすると、`hx-target`に指定した箇所が、`hx-get`のレスポンスに変更される。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="BabQVOd" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/BabQVOd">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# リクエストの発火

## イベントの指定

`hx-trigger`でイベントを指定する。イベントの種類については[Event - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Event) に色々載っている。

例えば以下のようなものがある。

| イベント名 | 対象属性 |
|:-:|:-:|
| change  | input, textarea, select  |
| submit  | form  |
| click  | button, a, span, divなど  |

```html
<button hx-get="/clicked" hx-trigger="click">クリック</button>
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="KKENBjK" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/KKENBjK">
  HTMX TRIGGER SAMPLE</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## トリガーフィルター

`hx-trigger="click[xxx]"`の `[]`の中 にbool値(インスタンスプロパティ)を入れることでイベントをフィルタリングできる。以下の例では、`hx-trigger="click[shiftKey]"`と指定しているが、SHIFTキーを押しながらクリックすると、`shiftKey`がtrueになるので発火する。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="LYabJbd" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/LYabJbd">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

以下のようにグローバル関数を入れることもできる。

```html
<button hx-get="/clicked" hx-trigger="click[checkGlobalState()]">クリック</button>
```

**JavaScript** を入れることも可能。

```html
<div hx-get="/clicked" hx-trigger="click[ctrlKey&&shiftKey]">コントロールキーとshiftキーが押下されました</div>
```

## 標準イベント修飾子

`hx-trigger="keyup changed throttle:1s queue:first"`のようにオプションをスペースを1つ開けて羅列することで、イベントを拡張することができる。(複数指定可能)

以下のオプションがある。

| オプション名 | 説明 |
|:-:|:-|
| once  | 1回のみ発火  |
| changed  | 要素が変更したときだけ発火  |
| delay:<時間>  | 発火する前に遅延が発生する  |
| throttle:<時間>  | 発火後に遅延が発生する  |
| from:<拡張CSSセレクタ>  | document,window,closest <CSSセレクタ>,find <CSSセレクタ>,next, next<CSSセレクタ>, previous, previous <CSSセレクタ>を指定できる。  |
| target:<CSSセレクタ>  | イベントのターゲットでCSS セレクタを介してフィルター処理する  |
| consume  | イベントは親 (または親をリッスンしている要素) に対する他の htmx リクエストを発火しない  |
| queue:<queue option>  |  first: 最初のイベントをキューに入れる<br>last: 最後のイベントをキューに入れる (default)<br>all:すべてのイベントをキューに入れる<br> none: 新しいイベントをキューに入れませんを指定できる |

以下の例では、`delay`と`changed`を用いることで、inputに文字が入力されてから、ユーザーが1秒間入力しなかった場合に発火する。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="wvOoEQK" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/wvOoEQK">
  HTMX Trigger Filter2</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

他にもカスタムイベントを使用すると高度なトリガーをすることもできる。

## 特別なイベント

他に特別なイベントとして以下3つのイベントがある。

| イベント | 説明 |
|:-:|:-|
|　load| ロード時に発火する |
|　revealed | 要素までスクロールしたときに発火する。<br> overflow-y: scrollのようにoverflowCSS使用時は **intersect once** を使う |
|　intersect | 要素が最初にビューポートと交差するときに1回発火する。<br>以下2つのオプションがある。<br> **root:\<selector\>** : 交差のルート要素の CSS セレクター <br> **threshold:\<float\>** : イベントを発火させる交差点の量を示す0.0～1.0の浮動小数点数 |

以下は`load`と`revealed`の例である。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="eYXBxxx" data-preview="true" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/eYXBxxx">
  HTMX Load Sample</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## ポーリング

`every <time>`で要素を定期的にポーリングできる。
**ポーリング**とは、更新などがあるかチェックするために、一定の間隔でサーバーに問い合わせることである。
以下の例では、`/sample`に対して、1秒ごとにGETリクエストを送信して、結果をこの`div`タグに反映する。

```html
<div hx-get="/latest_updates" hx-trigger="every 1s">
  hello ポーリング
</div>
```

フィルタリングを<time>の後に入れることも可能。

```html
<div hx-get="/latest_updates" hx-trigger="every 1s [someConditional]">
  hello ポーリング
</div>
```

## ロードポーリング

以下のようにloadにdelayをつけるとロードし続ける。

```html
<button hx-get="/messages"
    hx-trigger="load delay:1s"
    hx-swap="outerHTML">
</button>
```

ロードポーリングを使うと[プログレスバー](https://htmx.org/examples/progress-bar/)も作成できる。

## 複数のトリガー

複数のトリガーを指定する場合は、**カンマ** で区切る
以下の例は、ページの読み込み時にすぐに `/sample` にGETリクエストが送られ、クリックするたびに 1 秒遅れて再度送られる。

```html
<div hx-get="/sample" hx-trigger="load, click delay:1s"></div>
```

## JavaScript経由(JavaScript API)

AJAX リクエストは JavaScript 経由でトリガーすることもできる。`htmx.trigger()`を使用する。パラメータは以下の3つ。

* elt : イベントをトリガーする要素
* name : トリガーするイベントの名前
* detail : イベントの詳細

以下のようにすると、id=sample の要素がmyEventの応答が42になればOKとなる。

```js
  htmx.trigger("#sample", "myEvent", {answer:42});
```

# リクエストインジケーター

Ajax通信がローディングしていることを明示する(スピナーを表示する等)には、`htmx-indicator`を使うと実現できる。

`htmx-indicator`の要素の不透明度がデフォルトで 0 になるように定義されており、非表示になりますが DOM には存在する。

htmx がリクエストを発行すると、htmx-request要素 (リクエスト元の要素または指定されている場合は別の要素) にクラスが配置されます。このhtmx-requestクラスにより、そのクラスを持つ子要素がhtmx-indicator不透明度 1 に遷移し、インジケーターが表示される。

以下の例では、ボタンをクリックすると`htmx-request`クラスが追加され、ローディング中にスピナーが表示される。[おすすめのSVGスピナー](https://samherbert.net/svg-loaders/)

```html
<button hx-get="/sample">
    Click Me!
    <img class="htmx-indicator" src="/spinner.svg">
</button>
```

以下は実際に動かせるコードの実装例である。クリックするとスピナーが表れる。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="mdoOgPQ" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/mdoOgPQ">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

`htmx-request`クラスを別の要素に追加したい場合は、 CSSセレクターでhx-indicator属性を使用して追加できる。

```css:CSS
.htmx-indicator{
    display:none;
}
.htmx-request .htmx-indicator{
    display:inline;
}
.htmx-request.htmx-indicator{
    display:inline;
}
```

```html
<div>
    <button hx-get="/sample" hx-indicator="#indicator">
        Click Me!
    </button>
    <img id="indicator" class="htmx-indicator" src="/spinner.gif"/>
</div>
```

# スワッピング

DOMのHTMLの変更方法を変えるには`hx-swap`を使う。

| 設定値 | 説明 |
|:-:|:-:|
| innerHTML | ターゲット要素内のhtmlを置換する  |
| outerHTML |  ターゲット要素全体を返されたコンテンツで置き換える |
| afterbegin | ターゲット内の最初の子の前にコンテンツを追加する  |
| beforebegin | ターゲットの親要素のターゲットの前にコンテンツを追加する  |
| beforeend |  ターゲット内の最後の子の後にコンテンツを追加する  |
| afterend | ターゲット親要素のターゲットの後にコンテンツを追加する  |
| delete | レスポンスに関係なくターゲット要素を削除する  |
| none | レスポンスからコンテンツを追加しない  |

上の説明を見るより、実際に見た方がわかりやすいと思うので、8つの動作違いを明示した例を以下に挙げる。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwRmNgR" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/VwRmNgR">
  HTMX Swapping Sample</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## モーフスワップ(Morph Swaps)

htmx は拡張機能を介してモーフスワップもサポートしている

モーフィングスワップでは、既存のDOMを単純に置き換えるのではなく、新しいコンテンツを既存のDOMにマージする。より多くのCPUを占有する代わりに、スワップ操作中に既存のノードをその場で変更することで、フォーカスやビデオの状態などをより適切に保持する。

| 設定値 | 説明 |
|:-:|:-:|
| [Idiomorph](https://github.com/bigskysoftware/idiomorph#htmx)  |  htmx 開発者によって作成されたモーフィング アルゴリズム  |
| [Morphdom Swap](https://htmx.org/extensions/morphdom-swap/)  | オリジナルの DOM モーフィング ライブラリであるmorphdomに基づいている  |
| [Alpine-morph](https://htmx.org/extensions/alpine-morph/)  |  alpine morphプラグインに基づいており、alpine.jsとうまく連携する  |

## View Transitions API

新しい実験的な[View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions?hl=ja#simple-customization) は、 開発者に、異なる DOM 状態間のアニメーション遷移を作成する方法を提供します。この機能は、まだまだ開発中で、全ブラウザで利用できるわけではない。htmxは、特定のブラウザでこのAPIが利用できない場合に以下の手順で実現できる。

1. `htmx.config.globalViewTransitions=true` にしてすべてのスワップにトランジションを使用する
1. `hx-swap=transition:true`を設定する
1. `htmx:beforeTransition`イベントをキャッチし、`preventDefault()`がそれを呼び出して移行をキャンセルできる

## スワップオプション

| オプション | 説明 |
|:-:|:-:|
| transition  | このスワップにビュートランジションAPIを<br>使用するかどうか(*true*/*false* ) |
| swap  | 古いコンテンツがクリアされ、新しいコンテンツが挿入されたときの間に使用するためのスワップ遅延。 (e.g.100ms) |
| settle  | 新しいコンテンツが挿入され、 <br> それが解決されるまでの間の遅延時間 (e.g.100ms) |
| ignoreTitle  | trueのとき新しいコンテンツにあるタイトルは無視され、<br>ドキュメントタイトルを更新しない (*true/false*)  |
| scroll  | ターゲット要素をその上または下部に<br>スクロールする (*top/bottom*) |
| show  | ターゲット要素を上または下部に<br>スクロールして表示する (*top/bottom*)  |

その他の詳細は[hx-swap](https://htmx.org/attributes/hx-swap/)を参照

# 同期

`hx-sync`を使用すると同期的な処理を行うことができる。

```html
<form hx-post="/store">
    <input id="title" name="title" type="text"
        hx-post="/validate"
        hx-trigger="change"
    >
    <button type="submit">Submit</button>
</form>
```

# パラメータ

値が存在する場合は、その値がパラメータとして渡される。
例えば、Formの場合はFormに入力した値がパラメータとして渡される。

`hx-params`を用いるとそれらのパラメータをフィルタリングできる。

`hx-params`に指定できる値は3つある。

| 設定値 | 説明 |
|:-:|:-:|
| * | すべてのパラメータを許可する  |
| none | 何も渡さない  |
| not \<param-list\> |  指定したパラメータを除外する(カンマで区切る) |
| \<param-list\> | 指定したパラメータのみ許可する(カンマで区切る)  |

全てをパラメータとして渡す場合は以下のようにする。

```html
<div hx-get="/sample" hx-params="*">Parameter filter</div>
```

`hx-include`を使用すると、他の要素の値を含むことができる。
`hx-trigger`と同じく拡張CSSセレクタが使用可能。

以下の例では、name=emailの要素の値をパラメータとして追加している。

```html
<div>
    <button hx-post="/register" hx-include="[name='email']">
        Register!
    </button>
    Enter email: <input name="email" type="email"/>
</div>
```

[htmx:configRequest](https://htmx.org/events/#htmx:configRequest)イベントを使用すると、js側でパラメータを変更できる。

# ダイアログの表示

以下のように`hx-confirm="xxxx"`とすると以下のようなアラートを出せる。

```html
<button hx-confirm="xxxx">
  押すな危険！
</button>
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="gOELdNb" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/gOELdNb">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# アニメーション

htmxを使用すると、JavaScriptを使用せずに、HTML と CSS のみを使用して、CSS トランジションを実現できる。例については[アニメーション](https://htmx.org/examples/animations/)に載っている。

# 継承

htmxの一部の属性は継承される。
以下の例では親のdivに`hx-confirm`を付加すると(ボタンA, ボタンB)、子のbuttonもその属性を受け継ぎアラートが出るようになる。 継承したくない場合(ボタンC)は`hx-confirm="unset"`と設定する。

```html
<div hx-confirm="ファイナルアンサー？">
  <p>好きなボタンを選んでね</p>
  <button hx-delete="https://jsonplaceholder.typicode.com/posts/1">
    ボタンA
  </button>
  <button hx-post="https://jsonplaceholder.typicode.com/posts/1">
    ボタンB
  </button>
  <button hx-confirm="unset" hx-get="/">
    ボタンC
  </button>
</div>
```

以下は上記を実際に動かした例である。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="abMBeXG" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/abMBeXG">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# Boosting

`hx-boost`を使用すると、通常のaタグやformタグを「ブースト」して、代わりに AJAX を使用できる。ユーザが JavaScript を有効にしていない場合でも、サイトは引き続き動作する。( [Progressive enhancement - Wikipedia](https://en.wikipedia.org/wiki/Progressive_enhancement))

`hx-boost="true"`とすることで、ページ全体をロードすることなく、bodyタグの中身だけを置き換えることができる。(SPAの実現) また、後述の[hx-push-url](#history)と一緒に使うことが多い。

```html
<script src="https://unpkg.com/htmx.org@1.9.10"></script>

<div hx-boost="true">
  <a hx-post="/sample">Blog</a>
</div>
```

formタグの場合は以下のようになる。

```html
<form hx-boost="true" action="/sample" method="post">
    <input name="username" type="text" placeholder="ユーザネームを入力">
    <button>Submit</button>
</form>
```

# History

`hx-push-url`属性を使うと**History API**を利用することが可能となり、URLの動的な置換やブラウザのバックボタンの使用などが可能になる。
以下の**sample.html**をブラウザで開くと、アドレスバーに`https://jsonplaceholder.typicode.com/posts/1`が追加され、ブラウザの履歴に追加される。

```html:sample.html
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<p>以下をクリックするとブラウザのアドレスバーのURLが変わります。</p>
<a hx-put="https://jsonplaceholder.typicode.com/posts/1" hx-push-url="true">クリック</a>
```

`hx-history-elt`属性を設定すると、ビゲーション中にページの状態をスナップショットおよび復元するために使用される要素を指定できる。デフォルトは`body`となる。子要素に絞り込むことも可能。

```html
<html>
<body>
<div id="content" hx-history-elt>
 ...
</div>
</body>
</html>
```

:::note warn
ほとんどの場合、履歴スナップショットを絞り込むことはお勧めしない。
:::

`hx-history=false`とすると、`localStorage`のキャッシュに保存されないようにできる。

# Requests & Responses

HTMXでは、サーバからのレスポンス内容でDOMをスワップするのが多いが、スワップせずに、ステータスコードによってイベントを発火することもできる。

* 404や501 : `htmx:responseError`
* 接続エラー : `htmx:sendError`

## リクエストヘッダー

htmxによるリクエストでは、サーバー側で多数の HTTP ヘッダーにアクセスできる

| オプション | 説明 |
|:-:|:-:|
| HX-Boosted  | リクエストがhx-boostを使用する要素経由であることを示す  |
| HX-Current-URL  | ブラウザの現在の URL  |
| HX-History-Restore-Request  | リクエストがローカル履歴<br>キャッシュでのミス後の履歴復元の場合は**true**  |
| HX-Prompt  |  hx-promptに対するユーザーのレスポンス |
| HX-Request  | 常にtrue  |
| HX-Target  | ターゲット要素のID  |
| HX-Trigger-Name  | 発火した要素の名前  |
| HX-Trigger  | 発火した要素のID  |
| Access-Control-Allow-Headers  | CORSのヘッダー  |

## レスポンスヘッダー

リクエストの同様、サーバ側でレスポンス返す時に、持たせられるheaderオプション。

| オプション |説明 |
|:-:|:-:|
| HX-Location  | スーパーリロードをしないクライアント側のリダイレクトを実行する  |
| HX-Push-Url  |  新しい URL を履歴スタックにプッシュする  |
| HX-Redirect  | クライアント側のリダイレクトをできるようにする  |
| HX-Refresh  | 「true」に設定すると、クライアント側でページが完全に更新される  |
| HX-Replace-Url  | ロケーションバーの現在の URL を置き換える  |
| HX-Reswap  | レスポンスを交換する方法を指定できる。可能な値については、hx-swap を参照。  |
| HX-Retarget  | コンテンツ更新のターゲットをページ上の別の要素に更新する CSS セレクター  |
| HX-Reselect  | レスポンスのどの部分を交換に使用するかを選択できる CSS セレクター。<br>hx-selectトリガー要素の既存のものをオーバーライドする  |
| HX-Trigger  | クライアント側のイベントをトリガーできる  |
| HX-Trigger-After-Settle  | 解決ステップの後にクライアント側イベントをトリガーできる  |
| HX-Trigger-After-Swap  | スワップステップの後にクライアント側イベントをトリガーする  |
| Access-Control-Expose-Headers  | CORSのヘッダー |

htmx 経由でフォームを送信すると、 Post/Redirect/Get Patternが必要なくなるというメリットがある。サーバー上で POST リクエストが正常に処理された後は、 302ステータスコードを返す必要はない。

# バリデーション

| イベント | 説明 |
|:-:|:-:|
| htmx:validation:validate  | 要素の**checkValidity()** が呼ばれる前に呼び出される。カスタムバリデーションを追加するために使用する。  |
| htmx:validation:failed  | **checkValidity()** が *false* を返し、無効な入力を示す場合に呼び出される  |
| htmx:validation:halted  | バリデーションエラーによりリクエストが発行されない場合に呼び出されます。具体的なエラーは **event.detail.errors** オブジェクトで見つけることができる  |

`htmx:validation:validate`イベントをキャッチして、入力値が`foo`になっているか`hx-on`属性を使用した入力の例です。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="eYXBqxG" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/eYXBqxG">
  Untitled</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

:::note warn
`hx-post-"xxxx"`をbuttonタグにつけるとバリデートされない。formタグにつけよう！
:::

# 拡張機能

`hx-ext`で拡張機能を指定できる。
`hx-ext="ignore:拡張機能名"`とすると継承した拡張機能を無効にできる。

| 拡張機能             | 説明                                             |
|:-:|:-:|
| [json-enc](#json-enc) | Content-typeに、デフォルトの **application/x-www-form-urlencoded** ではなく、**application/json** を使用する    |
| morphdom-swap       | スワッピングで morphdom ライブラリを使用する |
| alpine-morph        | スワッピングでAlpine.js の morphプラグインを使用する |
| [client-side-templates](#client-side-templates) | JSONレスポンスを受け取るときのテンプレートエンジンの導入      |
| path-deps           | intercoolerjsに似たパスベースの依存関係を表現するための拡張機能  |
| class-tools         | HTML要素に対するタイミングのあるクラスの追加と削除を操作するための拡張機能 |
| multi-swap          | 異なるスワップメソッドを使用して複数の要素をスワップするための拡張機能 |
| response-targets    | HTTPコードが200を超えるレスポンスのために要素をスワップするための拡張機能  |

他にも[色々な拡張機能](https://htmx.org/extensions/#included)がある。

## json-enc

以下を追加する。

```html
<script src="https://unpkg.com/htmx.org/dist/ext/json-enc.js"></script>
```

以下のようにすると、jsonで

```html
<div hx-post='/test' hx-ext='json-enc'>クリック</div>
```

## client-side-templates

さて、今まで Ajax通信のレスポンスがjsonにしていたので、DOMをスワップするとjsonになり、すごく違和感があった。`client-side-templates`を使うと、その違和感を解消できる。

| 拡張機能          | 説明                  |
|:-:|:-:|
| mustache         | テンプレートエンジンMustacheを使う。   |
| handlebars   | テンプレートエンジンHandlebarsを使う。 |
| nunjucks         | Nunjucksを使用する。`nunjucks.render()`で書く。  |
| xslt             | XSLTを使う。|

導入方法は以下。

```html
<script src="https://unpkg.com/htmx.org/dist/ext/client-side-templates.js">
</script>
```

### Mustacheの例

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="OJqpJOz" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/OJqpJOz">
  HTMX Mustache Sample</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### XSLTの例

以下はXSLTの例である。XSLTを使うとXML形式のレスポンスを扱うことができるようになる。

まず、実際に動く例を挙げる。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="vYPxYvJ" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/vYPxYvJ">
  HTMX XSLT Sample</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

上記の例では、以下のようにscriptタグの中でxmlのレスポンスを処理している。

```html
<script id="foo" type="application/xml">
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
        名前: <xsl:value-of select="/hash/name" /> メールアドレス: <xsl:value-of select="/hash/email" />
      </xsl:template>
    </xsl:stylesheet>
</script>
```

### カスタム拡張機能

以下のようにjsでカスタム拡張機能を作ることができる。

```html
<script>
htmx.defineExtension("my-ext", { // 拡張機能名
  onEvent : function(name, evt) {
      // ここに拡張機能の動作を書く
  }
});
</script>
```

`hx-ext="my-ext"`として読み込める。
以下は実際に動かしてみた例である。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYbZjmZ" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/zYbZjmZ">
  HTMX Custom Extension</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

ボタンをクリックすると、カスタム機能が動作する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156096/f9e5c067-3ea7-a6d9-54e5-51cfdac8138e.png)

# WebSockets & SSE

**WebSocket**はサーバ側とユーザ側が常にオンライン状態を維持することによって、双方向通信を実現できる。リアルタイムに情報を共有できるチャットアプリケーションなどで用いられる。
**SSE**(Server-Sent Events)とは、サーバー送信イベントと呼ばれ、Webブラウザーとサーバー間の一方向の非同期通信方法のこと。SSEは、長時間接続でもリソース消費が少ないため、リアルタイムな通信に向いている。

:::note warn
WebSocketやSSEは`hx-ws`属性や`hx-sse`属性でも実現できるが、これらは拡張機能に完全移行されるので、拡張機能で実装しよう。この記事でも、拡張機能での実現方法のみ解説する。
:::

## [Web Socket](https://htmx.org/extensions/web-sockets/)

導入するには、まず以下スクリプトを読み込む。

```html
<script src="https://unpkg.com/htmx.org/dist/ext/ws.js"></script>
```

`hx-ext="ws"`を指定できるようになり、Web Socketを使えるようになる。
また、2つの属性が使えるようになる。

| 属性| 説明|
|:-:|:-:|
| ws-connect="\<url\>"<br>ws-connect="\<prefix\>:\<url\>"| WebSocket接続先URL |
| ws-send  | 要素のトリガー値に基づいて、最も近いWebSocketにメッセージを送信する。  |

以下のように指定する。

```html
<div hx-ext="ws" ws-connect="/chatroom">
    <div id="notifications"></div>
    <div id="chat_room">
        ...
    </div>
    <form id="form" ws-send>
        <input name="chat_message">
    </form>
</div>
```

2つの設定オブションがある。

| オプション名 | 説明 |
|:-:|:-:|
| createWebSocket  | カスタムWebSocketインスタンスの作成に<br>使用できるファクトリ関数  |
| wsBinaryType  | ソケットのbinaryTypeのプロパティを定義する文字列。<br>デフォルトはblob  |

## [SSE](https://htmx.org/extensions/server-sent-events/)

```html
<script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script>
```

`hx-ext="sse"`を指定できるようになり、SSEを使えるようになる。
SSEでは、以下2つの属性が使えるようになる。

| 属性 | 説明 |
|:-:|:-:|
| sse-connect="<url>"  | 接続先URL  |
| sse-swap="<message-name>"  |  DOM にスワップするメッセージの名前<br>`hx-trigger="sse:<message-name>"でもOK |

以下のように指定する。

```html
<div hx-ext="sse" sse-connect="/chatroom" sse-swap="message">
  Contents of this box will be updated in real time
  with every SSE message received from the chatroom.
</div>
```

# ロギング

HTMXは多くの[拡張イベント](https://htmx.org/reference/#events)があり、それらはロギングとしても役立つ。

例えば、特定のhtmxイベントを追加したい場合は以下のようにする。

```js
document.body.addEventListener('htmx:load', function(evt) {
    myJavascriptLib.init(evt.detail.elt);
});
```

htmx ヘルパー関数で実現することもできる。

```js
htmx.on("htmx:load", function(evt) {
    myJavascriptLib.init(evt.detail.elt);
});
```

## 3rdパーティライブラリの初期化

`htmx:load`を使うときにライブラリの初期化をするのは、非常に一般的であるため、htmxにはヘルパー関数が用意されている。
上記の例とやっていることは同じだが、こちらの方が多少綺麗にかける。

```js
htmx.onLoad(function(target) {
    myJavascriptLib.init(target);
});
```

## イベントを使用してリクエストを構成する

`htmx:configRequest`イベントを使うと、AJAXリクエストが発行される前に、JAX リクエストを変更できる。

```js
document.body.addEventListener('htmx:configRequest', function(evt) {
    evt.detail.parameters['auth_token'] = getAuthToken(); // add a new parameter into the request
    evt.detail.headers['Authentication-Token'] = getAuthToken(); // add a new header into the request
});
```

## イベントによるスワップ動作の変更

`htmx:beforeSwap`イベントを使うと、htmxのスワップの動作を変更できる。

```js
document.body.addEventListener('htmx:beforeSwap', function(evt) {
    if(evt.detail.xhr.status === 404){
        // alert the user when a 404 occurs (maybe use a nicer mechanism than alert())
        alert("Error: Could Not Find Resource");
    } else if(evt.detail.xhr.status === 422){
        // allow 422 responses to swap as we are using this as a signal that
        // a form was submitted with bad data and want to rerender with the
        // errors
        //
        // set isError to false to avoid error logging in console
        evt.detail.shouldSwap = true;
        evt.detail.isError = false;
    } else if(evt.detail.xhr.status === 418){
        // if the response code 418 (I'm a teapot) is returned, retarget the
        // content of the response to the element with the id `teapot`
        evt.detail.shouldSwap = true;
        evt.detail.target = htmx.find("#teapot");
    }
});
```

# デバッグ

htmxを用いたイベント駆動型プログラミングは、デバッグが難しくなる可能性がある。

まず、一番シンプルなデバッグ方法は以下のようにする。

```js
htmx.logAll();
```

DOM 要素がトリガーとして使用するためにどのイベントを起動しているのかがわからないときは、`monitorEvents()`をブラウザコンソールで叩くと、イベントを調べられる。(ただし、コンソールでしか動かない)

例えば、以下のようにすると、対象のIDを持つ要素で発生しているすべてのイベントを確認できる。

```js
monitorEvents(htmx.find("#sample"));
```

## デモ環境の作成

jsfiddleやcodepenなどを使うとデモ環境を作成できる。

デモ環境を作成するには、まず以下のスクリプトを貼り付ける。
これは **htmx** のlatestと **Hyperscript** を常に読み込むスクリプトである。

```html
<script src="https://demo.htmx.org"></script>
```

そして、URL属性をした `<template>`タグ を追加し、そこにモックしたレスポンスを書くことができる。

以下のデモコードはクリックした数をカウントアップする。

```html
<button hx-post="/foo" hx-target="#result">
    Count Up
</button>
<output id="result"></output>

<script>
    globalInt = 0; // グローバル変数
</script>
<template url="/foo" delay="500"> 
    ${globalInt++}
</template>
```

以下は、上記コードを実際にCodePenで動かしたものである。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="wvOJrBv" data-user="odlqzyes-the-sans" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/odlqzyes-the-sans/pen/wvOJrBv">
  HTMX Demo Sample</a> by Tomoki Ota (<a href="https://codepen.io/odlqzyes-the-sans">@odlqzyes-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 他のツールとHTMX統合

以下はhtmxとの相性がいい。

* VanillaJS　: ピュアなjavascript
* AlpineJS : scriptタグで導入できる
* hyperscript : htmxを作成した同じチームによって作成された言語。
* jQuery

## hx-on

htmlでは、一般的に[onevent](https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#using_onevent_properties)と以下のようにインラインスクリプトを組み込む。しかし、[特定のDOMイベント](https://www.w3schools.com/tags/ref_eventattributes.asp)しか組み込めないというデメリットがある。

```html
<button onclick="alert('You clicked me!')">
    Click Me!
</button>
```

そこで、htmxでは`hx-on`属性を使う。

以下のように`hx-on:イベント名="スクリプト"`の形で使用する。。

```html
<button hx-on:click="alert('You clicked me!')">
    Click Me!
</button>
```

htmxの拡張イベントの`htmx:config-request`を使うと、クリックするとリクエストにパラメータを追加するhtmxボタンを実現できる。

```html
<button hx-post="/example"
        hx-on:htmx:config-request="event.detail.parameters.example = 'Hello Scripting!'">
    Post Me!
</button>
```

## サードパーティのライブラリと組み合わせる

先ほど **jQuery**　などと相性が良いことを述べたが、他にも
例えば、SortableJSというライブラリと組み合わせると[Sortable](https://htmx.org/examples/sortable/) のような例が簡単に実現できる。

# htmxの設定

htmxには色々な設定オプションがある。
[Configuring htmx](https://htmx.org/docs/#config)を参照

JavaScriptで直接設定することも、以下のように`meta`タグで導入することもできる。

```html
<meta name="htmx-config" content='{"defaultSwapStyle":"outerHTML"}'>
```

# サーバサイド

GitHubには、htmxとサーバー側のフレームワークを統合している例がたくさんある。

[htmx ~ Server-Side Examples](https://htmx.org/server-examples/)にたくさんsampleが記載されている。

# より発展的な実装例

[htmx ~ Examples](https://htmx.org/examples/)にはhtmxを使用したさまざまな例が挙げられている。

# おわりに

HTMXに関して日本語ドキュメントがまだまだ少ないので、これからどんどん出てくるのが期待できる。英語のドキュメントは充実しており、色々なサーバサイドの例もあるので、ぜひ挑戦してみて欲しい。

拡張機能など一部しか解説できていないが、追々他の拡張機能についても説明載せる予定です。