1133
1081

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-01-17

HTMXとは

https://htmx.org/

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

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

2023 JavaScript Rising Starsでは、 フロントエンド・フレームワーク部門で見事2位に輝いた!(一位はReact、全部門だとshadcn/ui) 似たような機能として、Ruby on RailsのHotWireがあるらしい。

image.png

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

アメリカの動向

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

image.png

日本

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

image.png

インストール

CDN

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

<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に保存して以下のように読み込む。

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

npm

npm install htmx.org

webpack

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

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

import 'htmx.org';

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

import 'path/to/my_custom.js';

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

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

fakeAPI

今回サーバ側はJSON PlaceholderというfakeAPIを使用する。このサーバはJSON形式のレスポンスを返す。

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

また、XML形式のレスポンスを必要とする場合はTheTestRequestを使う。

メソッド URL
GET /authors/1.xml

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

Ajax

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

 <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通信が行われて、ボタンの文字が変わる。

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

ターゲット

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

<p>あいうえお</p>
<button hx-get="https://jsonplaceholder.typicode.com/posts/1" hx-trigger="click">クリック</button>
拡張CSSセレクタ 説明
this 自分自身を指定する。デフォルト hx-target="this"
closest <CSSセレクタ> CSSセレクタに一致する
一番近い親を指定する
 hx-target="closest tr"
find <CSSセレクタ> CSSセレクタに一致する
一番近い子を指定する
hx-target="find div"
next <CSSセレクタ> CSSセレクタに一致する
DOM 内の次の要素を指定する
hx-target="next target"
previous <CSSセレクタ> CSSセレクタに一致する
前の要素を指定する
hx-target="previous target"

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

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

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

リクエストの発火

イベントの指定

hx-triggerでイベントを指定する。イベントの種類についてはEvent - Web API | MDN に色々載っている。

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

イベント名 対象属性
change input, textarea, select
submit form
click button, a, span, divなど
<button hx-get="/clicked" hx-trigger="click">クリック</button>

See the Pen HTMX TRIGGER SAMPLE by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

トリガーフィルター

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

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

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

JavaScript を入れることも可能。

<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 ,find ,next, next, previous, previous を指定できる。
target: イベントのターゲットでCSS セレクタを介してフィルター処理する
consume イベントは親 (または親をリッスンしている要素) に対する他の htmx リクエストを発火しない
queue: first: 最初のイベントをキューに入れる
last: 最後のイベントをキューに入れる (default)
all:すべてのイベントをキューに入れる
none: 新しいイベントをキューに入れませんを指定できる

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

See the Pen HTMX Trigger Filter2 by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

特別なイベント

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

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

以下はloadrevealedの例である。

See the Pen HTMX Load Sample by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

ポーリング

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

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

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

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

ロードポーリング

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

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

ロードポーリングを使うとプログレスバーも作成できる。

複数のトリガー

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

<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となる。

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

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

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

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

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

以下の例では、ボタンをクリックするとhtmx-requestクラスが追加され、ローディング中にスピナーが表示される。おすすめのSVGスピナー

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

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

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

CSS
.htmx-indicator{
    display:none;
}
.htmx-request .htmx-indicator{
    display:inline;
}
.htmx-request.htmx-indicator{
    display:inline;
}
<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つの動作違いを明示した例を以下に挙げる。

See the Pen HTMX Swapping Sample by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

モーフスワップ(Morph Swaps)

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

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

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

View Transitions API

新しい実験的なView Transitions API は、 開発者に、異なる DOM 状態間のアニメーション遷移を作成する方法を提供します。この機能は、まだまだ開発中で、全ブラウザで利用できるわけではない。htmxは、特定のブラウザでこのAPIが利用できない場合に以下の手順で実現できる。

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

スワップオプション

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

その他の詳細はhx-swapを参照

同期

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

<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> 指定したパラメータのみ許可する(カンマで区切る)

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

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

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

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

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

htmx:configRequestイベントを使用すると、js側でパラメータを変更できる。

ダイアログの表示

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

<button hx-confirm="xxxx">
  押すな危険!
</button>

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

アニメーション

htmxを使用すると、JavaScriptを使用せずに、HTML と CSS のみを使用して、CSS トランジションを実現できる。例についてはアニメーションに載っている。

継承

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

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

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

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

Boosting

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

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

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

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

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

<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が追加され、ブラウザの履歴に追加される。

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>
<body>
<div id="content" hx-history-elt>
 ...
</div>
</body>
</html>

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

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 リクエストがローカル履歴
キャッシュでのミス後の履歴復元の場合は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 セレクター。
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属性を使用した入力の例です。

See the Pen Untitled by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

拡張機能

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

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

他にも色々な拡張機能がある。

json-enc

以下を追加する。

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

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

<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を使う。

導入方法は以下。

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

Mustacheの例

See the Pen HTMX Mustache Sample by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

XSLTの例

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

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

See the Pen HTMX XSLT Sample by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

<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でカスタム拡張機能を作ることができる。

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

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

See the Pen HTMX Custom Extension by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

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

image.png

WebSockets & SSE

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

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

Web Socket

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

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

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

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

以下のように指定する。

<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インスタンスの作成に
使用できるファクトリ関数
wsBinaryType ソケットのbinaryTypeのプロパティを定義する文字列。
デフォルトはblob

SSE

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

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

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

以下のように指定する。

<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は多くの拡張イベントがあり、それらはロギングとしても役立つ。

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

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

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

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

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

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

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

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

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

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のスワップの動作を変更できる。

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を用いたイベント駆動型プログラミングは、デバッグが難しくなる可能性がある。

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

htmx.logAll();

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

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

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

デモ環境の作成

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

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

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

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

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

<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で動かしたものである。

See the Pen HTMX Demo Sample by Tomoki Ota (@odlqzyes-the-sans) on CodePen.

他のツールとHTMX統合

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

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

hx-on

htmlでは、一般的にoneventと以下のようにインラインスクリプトを組み込む。しかし、特定のDOMイベントしか組み込めないというデメリットがある。

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

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

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

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

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

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

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

先ほど jQuery などと相性が良いことを述べたが、他にも
例えば、SortableJSというライブラリと組み合わせるとSortable のような例が簡単に実現できる。

htmxの設定

htmxには色々な設定オプションがある。
Configuring htmxを参照

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

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

サーバサイド

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

htmx ~ Server-Side Examplesにたくさんsampleが記載されている。

より発展的な実装例

htmx ~ Examplesにはhtmxを使用したさまざまな例が挙げられている。

おわりに

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

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

1133
1081
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1133
1081

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?