HTMXとは
HTMXは、JavaScript を記述せずに、Ajax通信や高度なUXを実現できるライブラリ。
軽量 で 高速 で、既存のサーバーサイドのフレームワークとシームレスなやり取りができる。また、AJAX通信の発火、フォームの送信処理、DOMの更新などを既存のHTML要素を拡張するだけで可能とする。WebSocketやSSEにも対応しているので、チャットアプリなどにも適している。
2023 JavaScript Rising Starsでは、 フロントエンド・フレームワーク部門で見事2位に輝いた!(一位はReact、全部門だとshadcn/ui) 似たような機能として、Ruby on RailsのHotWireがあるらしい。
2024年はHTMXがくると言われているぐらい世界で騒がれているのだが、あまり日本では流行っていない。以下はGoogleトレンドで調べた結果である。
アメリカの動向
アメリカやイギリスでは、2023年から HTMX がきてる。
全世界を対象にしてもほぼ同じ結果。
日本
昔から何も変わっていない。つまり、全然人気ではないということ。
明らかに最先端のアメリカやイギリスと比べると盛り上がりがない。これから盛り上げよう!!
インストール
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: 新しいイベントをキューに入れませんを指定できる |
以下の例では、delay
とchanged
を用いることで、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の浮動小数点数 |
以下はload
とrevealed
の例である。
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属性を使用して追加できる。
.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が利用できない場合に以下の手順で実現できる。
-
htmx.config.globalViewTransitions=true
にしてすべてのスワップにトランジションを使用する -
hx-swap=transition:true
を設定する -
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
が追加され、ブラウザの履歴に追加される。
<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.
ボタンをクリックすると、カスタム機能が動作する。
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に関して日本語ドキュメントがまだまだ少ないので、これからどんどん出てくるのが期待できる。英語のドキュメントは充実しており、色々なサーバサイドの例もあるので、ぜひ挑戦してみて欲しい。
拡張機能など一部しか解説できていないが、追々他の拡張機能についても説明載せる予定です。