htmxの「hx-on」属性でイベントハンドラを動的に設定する方法


hx-on の基本的な構文は以下の通りです。

<element hx-on="event=handler">
  </element>

上記の例では、element 要素に event イベントが発生した際に handler 関数が実行されます。

hx-on 属性で使用できるイベントは、以下の通りです。

  • error
    要素でエラーが発生したとき
  • load
    要素が読み込まれたとき
  • submit
    フォームが送信されたとき
  • keypress
    要素のキーが押され、かつそれが有効な文字であるとき
  • keydown
    要素のキーが押されたとき
  • keyup
    要素のキーが離されたとき
  • change
    要素の値が変更されたとき
  • blur
    要素からフォーカスが外れたとき
  • focus
    要素にフォーカスが当たったとき
  • dblclick
    要素がダブルクリックされたとき
  • click
    要素がクリックされたとき

hx-on 属性には、イベントハンドラ関数に加えてオプションパラメータを指定することもできます。オプションパラメータには、以下のようなものがあります。

  • capture
    イベントのキャプチャを有効にする
  • bubbles
    イベントのバブリングを有効にする
  • stopPropagation
    イベントの伝播を抑制する
  • preventDefault
    イベントのデフォルト動作を抑制する

hx-on 属性の具体的な例をいくつかご紹介します。

  • ボタンをクリックしたときにアラートを表示する
<button hx-on="click=showAlert">クリック</button>

<script>
function showAlert() {
  alert("ボタンがクリックされました!");
}
</script>
  • 入力フィールドに入力された値をコンソールに出力する
<input type="text" hx-on="keyup=logValue">

<script>
function logValue(event) {
  console.log(event.target.value);
}
</script>
  • フォームを送信したときにデータを非同期に送信する
<form hx-on="submit=submitForm">
  <input type="text" name="name">
  <button type="submit">送信</button>
</form>

<script>
function submitForm(event) {
  event.preventDefault();

  const data = new FormData(event.target);
  fetch('/submit', {
    method: 'POST',
    body: data
  })
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });
}
</script>


サーバーレスの「いいね!」ボタン

この例では、hx-on 属性を使用して、ボタンをクリックしたときに非同期にいいね!数を更新するサーバーレスの「いいね!」ボタンを作成します。

<div id="like-button" hx-init="count=0" hx-get="/likes" hx-target="#like-count">
  <button hx-on="click=like">いいね!</button>
  <span id="like-count">0</span>
</div>

<script>
function like() {
  this.disabled = true;

  fetch('/likes', {
    method: 'PUT'
  })
  .then(response => response.json())
  .then(data => {
    this.disabled = false;
    document.getElementById('like-count').textContent = data.count;
  });
}
</script>

動的なコメントフォーム

この例では、hx-on 属性を使用して、新しいコメントが送信されたときにコメントリストを動的に更新するコメントフォームを作成します。

<div id="comments">
  <h2>コメント</h2>
  <ul id="comment-list"></ul>

  <form hx-on="submit=addComment">
    <label for="comment-text">コメント:</label>
    <textarea id="comment-text" name="comment"></textarea>
    <button type="submit">送信</button>
  </form>
</div>

<script>
function addComment(event) {
  event.preventDefault();

  const commentText = document.getElementById('comment-text').value;

  fetch('/comments', {
    method: 'POST',
    body: JSON.stringify({ comment: commentText })
  })
  .then(response => response.json())
  .then(data => {
    const newComment = document.createElement('li');
    newComment.textContent = data.comment;
    document.getElementById('comment-list').appendChild(newComment);

    document.getElementById('comment-text').value = '';
  });
}
</script>

ドラッグ可能なタスクリスト

この例では、hx-on 属性を使用して、ドラッグ可能なタスクリストを作成します。

<ul id="task-list" hx-init="sortable=true">
  <li hx-swap="before">タスク 1</li>
  <li hx-swap="before">タスク 2</li>
  <li hx-swap="before">タスク 3</li>
</ul>

<script>
document.getElementById('task-list').addEventListener('dragstart', function(event) {
  event.dataTransfer.setData('text/plain', event.target.textContent);
});

document.getElementById('task-list').addEventListener('dragover', function(event) {
  event.preventDefault();
});

document.getElementById('task-list').addEventListener('drop', function(event) {
  const draggedItem = event.dataTransfer.getData('text/plain');
  const dropTarget = event.target;

  if (dropTarget !== draggedItem) {
    const list = document.getElementById('task-list');
    const draggedItemIndex = list.indexOf(draggedItem);
    const dropTargetIndex = list.indexOf(dropTarget);

    list.insertBefore(draggedItem, dropTargetIndex);
  }
});
</script>


htmx に代わる選択肢として以下が挙げられます

  • Alpine.js
    Alpine.js は、小さな Web アプリケーションやインタラクティブな Web ページを構築するための軽量な JavaScript ライブラリです。宣言的な属性を使用して、DOM 操作、イベントハンドラ、データバインディングなどを実装することができます。
  • Svelte
    Svelte は、コンポーネントベースの軽量な JavaScript フレームワークです。React や Vue.js と同様に、コンポーネントベースの開発、データバインディング、ルーティングなどの機能を提供しますが、コード量が少ないのが特徴です。
  • Vue.js、React.js、Angular などの JavaScript フレームワーク
    これらのフレームワークは、複雑なシングルページアプリケーション (SPA) を構築するのに適しています。コンポーネントベースの開発、データバインディング、ルーティングなどの機能を提供しますが、学習曲線が比較的高くなります。
  • jQuery
    jQuery は、JavaScript の開発を容易にする人気のライブラリです。Ajax、イベント処理、DOM 操作などの機能を提供しており、htmx に似た構文を使用することができます。ただし、jQuery は比較的大きいため、パフォーマンスに影響を与える可能性があります。
  • Vanilla JavaScript
    従来の JavaScript を使用して、Ajax リクエスト、イベントハンドラ、DOM 操作などを実装することができます。この方法は、柔軟性と制御性に優れていますが、コード量が多くなり、複雑になる可能性があります。
ツール長所短所
htmxシンプル、軽量、使いやすい機能が限られている
Vanilla JavaScript柔軟性、制御性が高いコード量が多くなる、複雑になる可能性がある
jQuery使いやすい、多くのライブラリと互換性がある比較的大きい、パフォーマンスに影響を与える可能性がある
JavaScript フレームワーク (Vue.js、React.js、Angular など)複雑な SPA の構築に適している学習曲線が比較的高くなる
Svelte軽量、コード量が少ない比較的新しく、コミュニティが小さい
Alpine.js軽量、使いやすい機能が限られている