今回はJavaScriptのコードを書かずにSPAのようなモダンなUIを構築できるライブラリ「htmx」をご紹介します。
目次
はじめに
最近のWebアプリケーションのUIには、ユーザ体験を向上させるインタラクティブな操作が多く実装されています。その実装にはクライアントサイドで動作するJavaScriptが用いられていますが、より簡単に実現するためにフレームワークやUIライブラリが活用されています。このような仕組みは、UIが複雑化する中で必要不可欠な存在です。
今回ご紹介するhtmxは、JavaScriptのコードを書かなくても、インタラクティブな処理をHTML要素の中に簡単に組み込めるJavaScriptライブラリです。本記事ではhtmxの特長や使い方を解説していきます。
htmxとは
htmxはインタラクティブなUIをシンプルなコードで実現できるJavaScriptライブラリです。AJAX通信やイベント処理の実装に伴う煩わしいコードを書くことなく、手軽に実装できるメリットがあります。2023年にはGitHubの年間スター数がReactに次いで2位となり、注目され始めているライブラリです。
HTML要素に動的な処理が内包されているかのように振る舞い、単純な属性を指定するだけで実現できます。下記はページ遷移するa
タグですが、htmxの属性を付加するだけで異なる動きを見せます。
<a href="/link">リンク</a>
これを次のように書き換えることで、HTMLのbody
タグ内だけを更新するシングルページアプリケーションのような動きが実現可能です。
<a href="/link" hx-boost="true">リンク</a>
フロントエンドではJavaScriptをほとんど記述することなく、HTMLの変更だけで多くの機能を実装できるため、既存のアプリケーションにも導入しやすいでしょう。また、実装に対する学習コストが低いわりに導入効果が高いです。
htmxの特長
htmxはJavaScriptライブラリとして以下の特長を持ちます。
軽量で依存関係のないライブラリ
htmxは独立したJavaScriptライブラリであり、他のプロダクトとの依存関係がありません。既に導入されたライブラリに影響を及ぼすことがないため、現行のプロジェクトでも取り入れやすいです。前身のライブラリであるintercooler.jsではjQueryが前提になっていましたが、htmxに名称を変えて刷新された今では依存関係が無くなり、より使いやすくなりました。
また、軽量なライブラリなのでページロードの邪魔になりません。ミニファイされたバンドルサイズは48KBほど(v1.9.12)で、小さな画像ファイルと変わりません。
インタラクティブな動作を簡単に実装できる
Webアプリケーションでよく使われるAJAX、WebSockets、DOM操作、イベント処理などの動的な処理を、少ないJavaScriptコードで実装できます。簡単な処理であれば、HTMLに少し付け加えるだけで済みます。
例えば、GETリクエストを発行したレスポンスを表示するには、下記のようにhx-get
のような属性をHTMLの要素を追記するだけでよく、JavaScriptのFetch APIは記述しません。
<div hx-get="/example" hx-swap="innerHTML">/exampleのレスポンス表示</div>
このようなコードの短縮は、新規開発はもとより既存のアプリケーションに適用することでパフォーマンス向上が期待できます。公式サイトによれば、htmxに置き換えたことでコード量の他にもビルド時間、読み込み時間、メモリ使用量の大幅な削減に大きく貢献した事例が挙げられています。
他のフレームワークとの共存・連携
htmxは動的な処理を簡潔に実装できるライブラリであり、部分的に導入することが可能です。他のライブラリとの依存関係もなく、HTMLの拡張属性とプレーンなJavaScriptで利用できるため、柔軟性が高いです。
そのため、昨今のJavaScriptフレームワークやコンポーネントライブラリで実装されたアプリケーションにも導入しやすいでしょう。htmxはインタラクティブな操作をHTMLに埋め込むことができるため、既存のUIコンポーネントに組み込みやすいです。
なお、HTMLレンダリングにおいて、サーバから非同期で受信したJSONデータをクライアントサイドで展開する従来の方法とは異なる点には注意が必要です。htmxではサーバから受信したHTMLを素早く書き換えることをコンセプトとしているため、サーバサイドの仕組みに応じて導入を検討しましょう。
htmxを使ってみよう
htmxの特長を実感できるように実際に使ってみましょう。実例としてAJAXのレスポンスでHTMLを部分的に書き換えるサンプルを作っていきます。なお、AJAX通信のエンドポイントはWebフレームワークのHonoで実装しています。
導入方法
まずはhtmxのライブラリを読み込みます。下記のようにCDN経由でも読み込めますが、本番環境ではダウンロードした上での利用が望ましいです。
<script src="https://unpkg.com/htmx.org@1.9.12" integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2" crossorigin="anonymous"></script>
今回のサンプルでは実行環境にダウンロードして読み込みます。
<script src="/js/htmx.min.js"></script>
<script src="/js/class-tools.js"></script>
また、htmxには拡張機構が備わっており、自作の機能を追加したり、備え付けの機能を呼び出したりできます。拡張機能を利用するにはライブラリを読み込むだけです。
AJAX通信のエンドポイントが別ドメインになる場合は、サーバ側のCORS設定で特定のヘッダを許可する必要があります。
利用する機能によって使われるヘッダは異なりますが、今回は次の2つのヘッダを許可します。
- HX-Request
- HX-Current-Url
htmxで使用されるヘッダは公式サイトに記載されていますので、必要に応じて許可を与えましょう。
htmxのチュートリアル
準備ができたらWebアプリケーションを作成していきましょう。作成するのは、氏名とメールアドレスの登録・確認画面を持つ簡単なUIです。
- ページを読み込むと、画面に現在のデータを表示する。
- [編集]ボタンを押すと、画面が編集用のUIに書き換わる。
- [更新]ボタンを押すと、更新したデータを表示し、変更した旨のメッセージを数秒だけ表示する。
フロント側のアクセス先ページのソースは下記になります。
<body>
<style>
.htmx-swapping {
opacity: .5;
transition: opacity 300ms linear;
}
.fade-me-out.htmx-swapping {
opacity: 0;
transition: opacity 1s ease-out;
}
.delete {
opacity: 0;
transition: opacity 1s ease-out;
}
</style>
<div hx-target="this" hx-swap="outerHTML">
<div><label>姓</label>: 田中</div>
<div><label>名</label>: 太郎</div>
<div><label>Email</label>: tanaka.taro@sample.xx.xx</div>
<button hx-get="http://127.0.0.1:3000/contact/edit">編集</button>
</div>
</body>
[編集]ボタンに付加しているhx-get
は、指定したURLにGETリクエストを発行することを表しています。今回はHonoを利用して連携先のバックエンドサーバーを127.0.0.1:3000
で起動しています。受信したレスポンスはhx-target
で指定しますが、親要素のdiv
で指定されている値が優先して参照されます。またhx-swap
で指定されるouterHTML
は、hx-target
で指定した要素全体を書き換えることを示しています。
サーバ側には、HTMLレスポンスを返す3つの機能を実装します。
- 編集画面を返す機能(
GET /contact/edit
) - データを更新して確認画面を返す機能(
PUT /contact
) - 現在のデータを取得して確認画面を返す機能(
GET /contact
)
GET(/contact/edit)
[編集]ボタンを押すと、データを表示していた部分を/contact/edit
のレスポンスに書き換えます。
<form hx-put="http://127.0.0.1:3000/contact" hx-target="this" hx-swap="outerHTML">
<div class="form-group">
<label for="last_name">姓</label>:
<input type="text" id="last_name" name="last_name" value={last_name} />
</div>
<div class="form-group">
<label for="first_name">名</label>:
<input type="text" id="first_name" name="first_name" value={first_name} />
</div>
<div class="form-group">
<label for="email_addr">Email</label>:
<input type="email" id="email_addr" name="email_addr" value={email_addr} />
</div>
<button class="btn">更新</button>
<button class="btn" hx-get="http://127.0.0.1:3000/contact">キャンセル</button>
</form>
// {}内には、実際にサーバ側で保存されているデータを出力します。
PUT(/contact)
[更新]ボタンを押すと、親要素のform
にあるhx-put
のURL/contact
にPUTメソッドでアクセスし、レスポンスを受け取ります。また、同要素のhx-target
とhx-swap
を参照して、form要素全体を書き換えます。
/contact
にPUTでアクセスすると、サーバ上の入力データを更新した上で下記のレスポンスを返します。加えて、更新した旨を伝えるメッセージがp
タグで1秒だけ表示されます。hx-ext
は拡張機能を示しており、指定されたclass-toolsはスタイルシートを時間差で適用することが可能です。ここでは、delete
クラスを1秒後に追加する指定をclasses
に記述しています。
<div hx-target="this" hx-swap="outerHTML">
<div><label>姓</label>: {last_name}</div>
<div><label>名</label>: {first_name}</div>
<div><label>Email</label>: {email_addr}</div>
<button hx-get="http://127.0.0.1:3000/contact/edit" class="btn btn-primary">編集</button>
</div>
<div hx-ext="class-tools">
<p classes="add delete:1s">情報を変更しました。</p>
</div>
// {}内には、実際にサーバ側で保存されているデータを出力します。
GET(/contact)
なお、[キャンセル]ボタンを押した場合は、/contact
にGETでアクセスして現在のデータを読み込んで元のUIを表示します。
<div hx-target="this" hx-swap="outerHTML">
<div><label>姓</label>: {lastName}</div>
<div><label>名</label>: {firstName}</div>
<div><label>Email</label>: {email}</div>
<button hx-get="http://127.0.0.1:3000/contact/edit" class="btn btn-primary">編集</button>
</div>
// {}内には、実際にサーバ側で保存されているデータを出力します。
ここまで挙げた機能は本来、JavaScriptでAJAX通信やDOM操作をコーディングする必要がありますが、HTMLの拡張属性しか使用していません。
今回は簡単な例でしたが、他機能の使用例やサーバサイドのアプリケーションとの連携する例が公式サイトに紹介されていますので、参考にしてみてください。
さいごに
本記事では、htmxの特長と簡単なチュートリアルによる導入イメージを解説しました。
htmxは、HTMLに少しの変更を加えるだけでインタラクティブなJavaScript処理を実現可能できるので、導入のハードルや学習コストが低いにもかかわらず、UI改善に大きな効果をもたらします。モダンなWebアプリケーションの開発をご検討されている方は是非チェックしてみてください。
メシウスでは業務アプリ開発に最適なJavaScriptライブラリを提供しています。
無償のトライアル版や、ブラウザ上で手軽に試せるデモアプリケーションも公開しているので、こちらも是非ご覧ください。