htmxの基本 - HTMLを返すサーバーと画面を更新する

6分 で読める | 2026.01.12

公式ドキュメント

htmxとは

記事情報: 2026年1月12日初出。本文のAPIと公式資料は2026年7月25日に再確認しています。

htmxは、HTML属性を使ってHTTPリクエストを送り、サーバーが返したHTMLで画面の一部を更新するライブラリです。

ReactやVueのように、ブラウザ側で大きな状態管理を行うことを主目的にしていません。サーバーがHTMLを生成する従来の構成を保ちながら、フォーム送信、検索結果、一覧の追加読み込みなどをページ遷移なしで更新できます。

この記事では、htmxの設計と向いている用途を確認します。

最小の例

公式ドキュメントでは、CDNから読み込む例が案内されています。本番では使用するバージョンを固定し、公式ページに掲載されたintegrity値を使うか、自分のサイトから配信してください。

<script
  src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.10/dist/htmx.min.js"
></script>

ボタンにhx-getを付けると、クリック時に指定URLへGETリクエストを送ります。

<button
  hx-get="/greeting"
  hx-target="#result"
  hx-swap="innerHTML"
>
  あいさつを表示
</button>

<div id="result"></div>

サーバーはJSONではなくHTML fragmentを返します。

<p>こんにちは、htmxです。</p>

htmxはレスポンスを#resultの中へ挿入します。

よく使う属性

属性役割
hx-getGETリクエストを送る
hx-postPOSTリクエストを送る
hx-putPUTリクエストを送る
hx-deleteDELETEリクエストを送る
hx-triggerリクエストを送るイベントを決める
hx-target更新対象の要素を決める
hx-swapレスポンスを挿入する方法を決める
hx-include追加で送信するinputを指定する
hx-indicator通信中に表示する要素を指定する

属性の数を増やす前に、リクエスト先、更新対象、置換方法の3点を確認すると理解しやすくなります。

フォーム送信

検索フォームを例にします。

<form
  hx-get="/users"
  hx-target="#user-list"
  hx-swap="innerHTML"
>
  <label>
    名前
    <input name="query" />
  </label>
  <button type="submit">検索</button>
</form>

<section id="user-list" aria-live="polite"></section>

サーバーは検索結果のHTMLを返します。

<ul>
  <li>佐藤</li>
  <li>佐々木</li>
</ul>

JavaScriptでfetch、JSON変換、DOM生成を個別に書かなくても更新できます。一方、HTMLを生成する責務はサーバー側にあります。

入力に合わせて検索する

hx-triggerを使うと、入力イベントの条件を指定できます。

<input
  type="search"
  name="query"
  hx-get="/users"
  hx-trigger="input changed delay:300ms"
  hx-target="#user-list"
/>

delay:300msは、入力のたびに即座に通信せず、入力が止まってからリクエストを送るための指定です。

検索語が空の場合、短すぎる場合、連続リクエストの順序が前後した場合にサーバーがどう応答するかも決めてください。

hx-swapの違い

hx-swapはレスポンスをどの位置へ入れるかを指定します。

動作
innerHTMLtargetの中身を置き換える
outerHTMLtarget自体を置き換える
beforeendtargetの末尾へ追加する
afterbegintargetの先頭へ追加する
deletetargetを削除する
noneDOMを置き換えない

outerHTMLでtarget自体を交換すると、次の更新で同じIDや属性が存在しなくなることがあります。サーバーが返すfragmentにも、次の操作に必要な属性を含めます。

サーバー側で必要なこと

htmxを使っても、認証、認可、入力検証、CSRF対策は不要になりません。

特にPOST・PUT・DELETEでは次を確認します。

  • ログイン中の利用者が操作できる対象か
  • CSRF tokenを送信・検証しているか
  • 同じ操作を再送しても問題ないか
  • validation errorをHTMLとして返せるか
  • HTTP statusを適切に返しているか

クライアント側でボタンを隠すだけでは認可になりません。サーバー側で必ず判定します。

アクセシビリティ

一部更新では、画面が変わったことを支援技術へ伝える必要があります。検索結果などにはaria-liveを検討し、エラー時は入力欄との関連を示します。

読み込み中のindicatorを表示するだけでなく、キーボードフォーカスが不自然に失われないか、履歴を使う画面で戻る操作が期待通りかも確認してください。

重要なページ遷移をすべて部分更新へ変える必要はありません。通常のリンクとフォーム送信は、JavaScriptが動かない場合の基礎にもなります。

URLと履歴

検索条件やページ番号など、再読み込みや共有が必要な状態はURLへ反映します。hx-push-urlを使うと、成功したリクエストのURLをブラウザ履歴へ追加できます。

<a
  href="/articles?page=2"
  hx-get="/articles?page=2"
  hx-target="#article-list"
  hx-push-url="true"
>
  次のページ
</a>

hrefも残しておけば、htmxが読み込まれない場合は通常のページ遷移として動作できます。戻る・進む操作、直接URLを開いた場合、サーバーがfull pageとfragmentをどう返し分けるかを確認してください。

エラー処理

通信失敗時に画面が無反応に見えないよう、htmxのeventを使ってメッセージを表示できます。

const errorMessages = {
  "htmx:responseError": "サーバーがエラーを返しました。",
  "htmx:sendError": "サーバーへ接続できませんでした。",
  "htmx:timeout": "通信がタイムアウトしました。",
};

for (const [eventName, text] of Object.entries(errorMessages)) {
  document.body.addEventListener(eventName, () => {
    const message = document.querySelector("#error-message");
    if (message) {
      message.textContent = `${text} もう一度お試しください。`;
    }
  });
}

responseErrorはHTTP error response、sendErrorは送信・接続の失敗、timeoutはtimeoutとして分けて扱います。利用者向けには再試行できる案内を出し、開発者向けにはHTTP status、request ID、サーバーログで原因を追えるようにします。validation errorとserver errorを同じ表示にせず、入力を修正できる場合は該当項目の近くへ説明を表示します。

networkを切った状態や、serverが400・401・403・500を返す場合も実際の端末で確認すると、成功時だけでは見つからない問題を発見できます。

向いている用途

htmxを検討しやすい例です。

  • サーバーレンダリング中心の管理画面
  • 検索、絞り込み、ページ送り
  • フォームのvalidation結果
  • コメントや一覧の追加
  • 小規模なモーダル内容の取得

クライアント側で複雑なオフライン状態を持つアプリ、キャンバスやリアルタイム描画が中心の画面、ブラウザ内で大量の状態変換を行う用途では、別の構成も比較します。

まとめ

  • htmxはHTML属性からHTTPリクエストを送る
  • サーバーはJSONではなくHTML fragmentを返す
  • hx-targethx-swapで更新位置を決める
  • 認証・認可・CSRF・validationはサーバー側で必要
  • サーバーレンダリング中心の画面へ段階的に導入できる

参考リソース

← 一覧に戻る
PR
PR
PR
PR