開発

htmx 4.0とは:2系からの変更点と移行手順をコードで解説【2026年版】

htmx 4.0とは:2系からの変更点と移行手順をコードで解説【2026年版】

htmx 4.0は、2026年8月28日に公開されたhtmxの次期メジャー版です。内部の通信がXMLHttpRequestからfetch()へ置き換わり、属性の継承が「明示しない限り効かない」方式に変わったため、2系で書いたテンプレートの一部はそのままでは動きません。この記事では、4.0の正式リリース情報と配布方針、破壊的変更を2系と4系の比較コードで示したうえで、公式のupgrade-checkコマンドと互換拡張を使った段階的な移行手順、そして移行する案件と据え置く案件の判断基準までを、2026年10月時点の一次情報で整理します。htmxの基本的な書き方は既公開の使い方記事に譲り、本稿は「2系との差分」と「移行作業」に絞ります。

まとめ:htmx 4.0はfetch化と明示継承を軸にした破壊的なメジャー更新

htmx 4.0の中身は、通信基盤のfetch()化、属性継承の明示化、4xx・5xx応答も画面へ差し替える既定動作、イベント名のhtmx:phase:action形式への統一の4本柱です。fetch()化だけは元に戻せませんが、残りは設定3行か互換拡張htmx-2-compatで2系の挙動に寄せられます。

急いで移行する必要はありません。公式は2系を無期限にサポートすると明言しており、npmでも2026年10月時点でlatestタグは2.0.11のままで、4.0.0はnextタグで配布されています。新規開発は4.0で始め、保守中の2系案件は画面改修などテンプレートに手を入れる機会にまとめて移行する。これが本稿の結論です。

htmx 4.0の正式リリース情報と2.0系との配布・サポート方針の違い

まず「いつ、どの形で配布されているか」を押さえます。ここを取り違えると、npm installで入ったのが2系なのに4系のドキュメントを読んでしまう、という食い違いが起きます。

4.0.0の公開日とnpmのnextタグ運用で2系が既定のまま残る仕組み

GitHubのリリース一覧では、v4.0.0が2026年8月28日にプレリリースではない正式版として公開されています。2026年7月23日の4.0.0-beta6までベータ版の公開を重ねたうえでの正式版です。

配布方針は独特です。公式のリリース告知は、npmで4.0をlatestにせず、2027年初頭のどこかまで2系をlatest、4.0系をnextに置くと説明しています。npmレジストリの配布タグを2026年10月10日に確認した値は次のとおりです。

$ curl -s https://registry.npmjs.org/-/package/htmx.org/dist-tags
{"latest":"2.0.11","next":"4.0.0"}

# 4.0を入れるときはバージョンかタグを明示する
$ npm install [email protected]
$ npm install htmx.org@next

つまりバージョンを指定しないnpm install htmx.orgでは2.0.11が入ります。ドキュメントも分かれており、htmx.orgのトップは2026年10月時点で2.0.11の読み込み例を掲載し、4系の資料はfour.htmx.orgに置かれています。参照先と導入版を必ず揃えてください。

XHRからfetch()への置き換えとストリーミング応答に対応した内部設計

4.0最大の内部変更は、Ajax通信の基盤がXMLHttpRequest(XHR)からfetch()へ移ったことです。公式の「What’s New in htmx 4」は、すべてのリクエストがネイティブのfetch()を使い、この変更は元に戻せないと明記しています。

狙いの1つはストリーミングです。作者のCarson Grossは2025年11月1日のエッセイ「The fetch()ening」で、fetch()の読み取り可能ストリームを使えば、1つの完成した応答ではなく、届いた順にコンテンツをDOMへ差し替えられると説明しています。XHRは応答全体を受け取るまで描画できないため、重い一覧の先頭だけ先に表示する、といった段階描画は2系では作りにくい処理でした。通信が非同期で進む仕組みそのものは同期処理と非同期処理の違いを実装方式から整理した解説で確認できます。

テンプレート側への影響は、hx-getやhx-postの書き方が変わらない点では小さい一方、XHR固有のイベント(htmx:xhr:*)は削除されました。XHRのイベントに処理を書いていたコードは、後述の新しいイベントへ書き換えが必要です。

配布サイズの実測比較:4.0.0と2.0.11のmin.jsを並べた結果

2026年10月10日にjsDelivrから両版のdist/htmx.min.jsを取得し、gzip(圧縮レベル9)をかけて計測しました。配信サーバーの圧縮設定で実際の転送量は前後するため、比較の目安として見てください。

版 min.js(非圧縮) gzip後 npmの配布タグ
htmx 4.0.0 36,716バイト 13,116バイト(約12.8KB) next
htmx 2.0.11 52,182バイト 16,944バイト(約16.5KB) latest

モーフィング(後述)をコアへ取り込みながら、gzip後で約23%小さくなっています。ただし差は4KB弱で、移行の動機にするほどの差ではありません。判断は次章の破壊的変更の量で行います。

htmx 2系のコードが動かなくなる破壊的変更5点と書き換えのコード例

移行で手を入れる箇所は5種類に集約できます。以下は、テンプレートへの影響範囲が広い順に並べた一覧です。実務ではまず1つ目の属性継承だけを全テンプレートで洗えば、作業量の大半が見積もれます。

属性継承の明示化::inherited修飾子を付けないと子要素へ効かない例

2系では、親要素に書いたhx-confirmやhx-targetが子要素へ自動で引き継がれていました。4.0ではこの暗黙の継承が既定で無効になり、引き継がせたい属性に:inheritedを付けます。作者は前掲のエッセイで、暗黙の継承を「htmx 1.0と2.0で最大の失敗」と述べています。

<!-- htmx 2:親のhx-confirmが子のボタンに自動で効く -->
<div hx-confirm="削除しますか?">
  <button hx-delete="/items/1">削除</button>
</div>

<!-- htmx 4::inheritedを付けた属性だけが子へ効く -->
<div hx-confirm:inherited="削除しますか?">
  <button hx-delete="/items/1">削除</button>
</div>

<!-- 親の値に子の値を足すときは:appendを重ねる -->
<div hx-include:inherited="#global-fields">
  <form hx-include:inherited:append=".extra">...</form>
</div>

怖いのは、修飾子を付け忘れてもエラーが出ない点です。確認ダイアログが出ないまま削除が走る、差し替え先がずれて画面の別の場所が書き換わる、といった症状として現れます。body要素にhx-targetやhx-headersを置いてページ全体へ効かせていた構成ほど影響が大きくなります。

4xx・5xxも差し替える既定動作とhx-statusによるコード別の分岐指定

2系はエラー応答(4xx・5xx)を画面へ差し替えませんでした。4.0は204と304を除くすべての応答を差し替えます。入力エラー時にサーバーが返したエラー表示用HTMLがそのまま出る点は便利ですが、2系の前提で「エラー時は何も起きない」と作った画面では、500エラーのページ断片が一覧の中へ入り込む事故になります。

応答コードごとの扱いは、新しいhx-status:コード属性で指定します。

<form hx-post="/save"
      hx-status:422="swap:innerHTML target:#errors select:#validation-errors"
      hx-status:5xx="swap:none push:false">
  ...
</form>

この例では、422(入力エラー)のときだけ#errorsへエラー表示を差し込み、5xxでは画面も履歴も変えません。5xxのように桁をまとめた指定もできます。

イベント名のhtmx:phase:action形式への統一と主要な置き換え対応表

イベント名はhtmx:phase:actionの形に統一されました。hx-on属性やaddEventListenerで旧名を使っている箇所は、置き換えないと処理が呼ばれなくなります。利用頻度の高いものを抜き出します。

htmx 2の旧イベント名 htmx 4の新イベント名
htmx:beforeRequest htmx:before:request
htmx:afterRequest htmx:after:request
htmx:configRequest htmx:config:request
htmx:beforeSwap htmx:before:swap
htmx:afterSwap htmx:after:swap
htmx:afterSettle htmx:after:settle
htmx:load htmx:after:init
htmx:afterOnLoad htmx:after:init
htmx:responseError htmx:response:error
htmx:sendError htmx:error(集約)
htmx:timeout など htmx:error(集約)

複数の旧イベントが1つの新イベントへ集約された点に注意してください。htmx:loadとhtmx:afterOnLoadはどちらもhtmx:after:initになるため、両方に別々の処理を書いていたコードは、統合後に二重実行されないか確認が必要です。htmx:validation:*とhtmx:xhr:*は対応先がなく削除されています。

hx-disableの意味変更とhx-vars・hx-params削除で書き換える属性

属性の改名・削除は件数こそ少ないものの、1つだけ順番を誤ると壊れる罠があります。

htmx 2の属性 htmx 4での扱い
hx-disable(htmxの処理を止める) hx-ignoreへ改名
hx-disabled-elt(通信中に無効化) hx-disableへ改名
hx-vars 削除。hx-valsのjs:接頭辞で代替
hx-params 削除。htmx:config:requestで制限
hx-request 削除。hx-configで指定

hx-paramsの削除後は、htmx:config:requestイベントで送信値を絞ります。改名の順序に罠があるのはhx-disableです。4.0では同じ名前が「通信中に無効化する要素」という別の意味になったため、先にhx-disableをhx-ignoreへ置き換え、その後でhx-disabled-eltをhx-disableへ改名します。逆順での一括置換は、2つの用途を区別できなくする原因です。公式も「アップグレードの前に」この改名を済ませるよう案内しています。

履歴のlocalStorageキャッシュ廃止と既定タイムアウト60秒への変更

2系はhx-push-urlで積んだ履歴のページをlocalStorageへ保存し、戻る操作で復元していました。4.0はこのキャッシュを持たず、戻る操作でページを取り直して差し替えます。ブラウザ側に古い画面の写しが残らなくなる一方、戻るたびにサーバーへリクエストが飛ぶ点は、負荷を見積もる際に考慮すべき条件です。完全な再読み込みにしたい場合はhtmx.config.history = "reload"、無効化ならfalseを指定します。

設定の既定値も2つ変わりました。defaultTimeoutは0(無制限)から60000ミリ秒、defaultSettleDelayは20から1です。60秒を超える帳票出力やCSV取り込みをhtmxのリクエストで待っている画面は、4.0ではタイムアウトで打ち切られます。

htmx 4.0で追加された新機能:morphスワップとhx-partialの書き方

破壊的変更の見返りとして、2系では拡張機能や追加の実装が必要だった処理がコアに入りました。移行の動機になりうる2つを取り上げます。

innerMorph・outerMorphで入力中のフォーム状態を保ったまま更新する

hx-swapにinnerMorphとouterMorphが加わりました。idiomorphのアルゴリズムで新旧のDOMを突き合わせ、変わった部分だけを書き換える差し替え方式です。

<div hx-get="/orders/summary" hx-trigger="every 10s" hx-swap="innerMorph">
  ...
</div>

通常のinnerHTMLは領域ごと作り直すため、入力途中のテキスト、フォーカス位置、開いていたアコーディオンの状態が消えます。10秒ごとに集計を更新する管理画面のように、利用者が操作している最中に再描画が走る画面で差が出ます。2系でも拡張を入れれば同じことはできましたが、4.0では追加の読み込みが不要です。

hx-partial要素で1回の応答から複数の領域を同時に更新する実装例

サーバーの応答に<hx-partial>要素を並べると、1回のリクエストで画面の離れた場所を別々に更新できます。

<!-- サーバーが返す応答HTML -->
<hx-partial hx-target="#messages" hx-swap="beforeend">
  <div>新しいメッセージ</div>
</hx-partial>
<hx-partial hx-target="#count">
  <span>5</span>
</hx-partial>

2系で同じことをするにはhx-swap-oobで各要素にidと差し替え方を埋め込む必要がありました。<hx-partial>は差し替え先と方式を通常のhx-target・hx-swapと同じ書き方で指定できるため、サーバー側テンプレートの見通しが良くなります。サーバーがHTML断片を返す設計の全体像は、CSR・SSR・SSGの違いと選定基準を整理したレンダリングの解説と合わせて読むと位置づけがつかみやすくなります。

htmx 2系から4.0へ移行する作業手順:upgrade-checkから段階移行まで

移行は「洗い出す→2系の挙動のまま4.0へ載せ替える→互換設定を1つずつ外す」の3段階で進めると、壊れた箇所の原因を切り分けやすくなります。

upgrade-checkコマンドで:inherited漏れと旧イベント名を洗い出す手順

公式は、移行が必要な箇所を探すコマンドラインツールを用意しています。テンプレートのディレクトリを渡して実行します。

$ npx [email protected] upgrade-check -- ./templates

走査対象の既定の拡張子は.html・.php・.js・.ts・.jinja・.jinja2・.j2・.erb・.hbsで、Vueなどのファイルを含めるときは--ext .vueのように追加します。結果はファイル名と行番号付きで、[inheritance](:inheritedが必要)、[renamed-attr]、[removed-attr]、[old-event]、[old-api]の5種類のタグで分類され、最後に件数が集計されます。この件数が、そのまま移行工数を見積もる際の判断材料です。

ただし、検出できるのはテンプレート内に書かれた属性とイベント名です。4xx・5xxの差し替え変更やタイムアウトの変更は挙動の差なので、ツールでは見つかりません。エラー応答を返すエンドポイントと、60秒を超えうる処理は別途一覧にしておきます。

設定3行またはhtmx-2-compat拡張で2系の挙動を保って載せ替える方法

洗い出した箇所をすべて直してから切り替える必要はありません。What’s Newのページは、次の3行で2系の既定動作へ戻せると案内しています。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script>
  htmx.config.implicitInheritance = true;            // 暗黙の継承を戻す
  htmx.config.noSwap = [204, 304, '4xx', '5xx'];     // エラー応答を差し替えない
  htmx.config.defaultTimeout = 0;                    // タイムアウトなしに戻す
</script>

旧イベント名やhx-ext属性も含めて戻したい場合は、互換拡張htmx-2-compatを読み込みます。公式は既存アプリの段階的な移行向けと位置づけています。

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ext/htmx-2-compat.js"></script>

どちらでもfetch()化だけは戻りません。XHRのイベントに依存した処理と、defineExtensionで書いた自作拡張(4.0ではregisterExtensionとイベントフック方式へ変更)は、載せ替えの時点で書き直しが必要です。

互換設定を外していく順番:継承→エラー応答→イベント名の3段階

載せ替えて動作を確認したら、互換設定を1つずつ外します。順番は次のとおりです。

  1. 属性継承:upgrade-checkの[inheritance]指摘に:inheritedを付け、implicitInheritanceを外す
  2. エラー応答:422などの入力エラーをhx-statusで受ける形に書き換え、noSwapを外す
  3. イベント名と改名属性:[old-event]と[renamed-attr]を置き換え、htmx-2-compatを外す
  4. タイムアウト:長時間処理を非同期ジョブ化するか個別に延長し、defaultTimeoutの上書きを外す

継承を最初に外すのは、影響が最も広く、付け忘れが「エラーにならない誤動作」として出るためです。1段階ごとに画面の回帰確認を挟めば、どの変更で壊れたかを特定できます。

htmx 4.0へ今すぐ移行する案件と2系に留める案件の判断基準

2系が無期限サポートである以上、移行は「やるか、いつやるか」の判断です。どちらにするかは、新機能を使う予定と、テンプレートに手を入れる予定があるかで決まります。htmxそのものを採用すべきかという手前の判断は、htmxの仕組みとメリット・デメリットを整理した判断ハブ記事で扱っています。

新規開発は4.0を選び保守中の2系案件は改修の機会まで据え置く条件

これから作る画面は4.0で始めます。明示継承とhx-statusを前提に書けば移行作業そのものが発生せず、2027年初頭にlatestが4系へ切り替わった後も追従が楽です。属性の基本的な書き方とサーバー連携の実装は、hx-属性の実装手順とFastAPI連携をまとめたhtmxの使い方で手順を追えます(同記事の例は2系の書き方のため、継承とエラー応答の箇所は本稿の差分を当てはめてください)。

保守中の2系案件は、画面改修や機能追加でテンプレートを触る案件が入るまで据え置きます。動いている画面を移行のためだけに書き換えると、回帰テストの工数が丸ごと上乗せされ、利用者から見た改善はゼロです。改修と同じリリースで移行すれば、テストを1回にまとめられます。ライブラリのメジャー更新を保守計画に組み込む進め方や、移行作業の外部委託は、一創の保守運用・内製化支援でご相談いただけます。

移行を見送るべき場面:自作拡張への依存とXHRイベント前提の実装

次のどちらかに当てはまる案件は、当面4.0へ移行しません。

  • defineExtensionで書いた自作拡張や、XHRのイベント(htmx:xhr:*)に処理を載せている:互換拡張でも戻らない部分で、書き直しが必須になる
  • 使っている外部拡張の4.0対応版が出ていない:SSE・WebSocketなど主要な拡張は4.0向けに書き直されており、2系向けの拡張はそのまま読み込めない前提で確認する
  • 60秒を超える同期処理をhtmxのリクエストで待っており、非同期化の予算がない

どれも「互換設定では吸収できず、コードの書き直しが先に必要になる」条件です。このような案件では、4.0の新機能で得られる効果より移行コストが上回ります。2系のまま無期限サポートの恩恵を受け、拡張の対応状況を半年ごとに確認する運用で十分です。

よくある質問

htmx 4.0について、移行を検討する開発者から出やすい質問をまとめました。

htmx 4.0はいつリリースされましたか?

正式版の4.0.0は2026年8月28日に公開されました。2025年11月に作者のエッセイで構想が示され、2026年7月23日の4.0.0-beta6までベータ版が続いたあとでの正式リリースです。ただしnpmでは2027年初頭までnextタグでの配布となり、latestは2系のまま据え置かれています。

npm install htmx.orgを実行すると4.0が入りますか?

入りません。2026年10月10日時点でlatestタグは2.0.11を指しているため、バージョンを指定しないインストールでは2系が入ります。4.0を使うにはnpm install [email protected]のようにバージョンを指定するか、@nextタグを付けます。CDNから読み込む場合も、URLに@4.0.0を含めて版を固定してください。

htmx 2はいつまで使えますか?

公式は2系を無期限にサポートすると明言しており、アップグレードを急ぐ必要はないとしています。1系やhtmxの前身であるintercooler.jsも同じ方針で扱われてきました。サポート終了を理由にした移行期限は現時点で存在しないため、移行時期は画面改修の予定や新機能の必要性から逆算して決めて差し支えありません。

htmx 4.0への移行にはどのくらいの作業が必要ですか?

テンプレートの書き方次第で大きく変わります。規模を測るには、まずnpx [email protected] upgrade-check -- ./templatesを実行し、指摘件数を種類別に数えるのが近道です。[inheritance]の件数が多いほど作業は膨らみます。加えて、エラー応答の差し替えとタイムアウトの変更はツールで検出できないため、該当するエンドポイントの確認工数を別に見込みます。

htmx 4.0でもCDNのscriptタグ1本で導入できますか?

できます。ビルド不要でscriptタグ1本から使える点は2系と変わりません。jsDelivrならhttps://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.jsを読み込みます。拡張機能はdist/ext/配下の個別ファイルを追加で読み込む方式です。配布ファイルはgzip後で約13KBと、2.0.11より小さくなっています。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.08 テックブログ 大阪公立大学のランサムウェア被害と仮想化基盤の停止|全授業休講に至った経緯とバックアップを守る設定
  2. 2026.10.09 テックブログ IDCFクラウドの不正アクセスとランサムウェア被害|利用者の初動と別基盤への復旧手順
  3. 2024.11.08 テックブログ OpenAPI GeneratorでJavaコードを自動生成する方法|CLI導入からSpring・ライブラリ選択まで
  4. 2026.10.09 テックブログ ニッスイのサイバー攻撃で日水物流の入出荷停止|委託先クラウド障害に荷主が備える手順
  5. 2026.10.09 テックブログ 京王電鉄のランサムウェア被害とグループ共通基盤:決済・ポイント・予約が止まった範囲と遮断の初動

RELATED POSTS 関連記事

目次