htmx 逆引きレシピ
htmxでボタンで一部だけ差し替えるには?

公開日:
最終更新日:

htmxでは、ボタン1つに hx-get / hx-target / hx-swap を付けるだけで、 ページ全体ではなく必要な範囲だけを再取得して差し替えられます。 管理画面の「詳細パネル」「承認ステータス」「集計カード」など、部分更新が多い業務UIで特に効きます。

使用するhtmx属性

  • hx-get:GETでHTMLを取りに行って差し替える
  • hx-post:POSTで更新して、結果のHTMLを差し替える
  • hx-target:差し替える先の要素(CSSセレクタ)を指定
  • hx-swap:差し替え方を指定(例:innerHTML / outerHTML
  • hx-indicator:通信中表示(ローディング)を出す要素を指定
  • hx-disabled-elt:通信中だけボタン等を disabled にして連打を防止

利用シーン

  • 「詳細パネルだけ再読み込み」:DB更新後の最新状態を、そのパネルだけ反映したい
  • 「承認ステータスだけ更新」:ステータスバッジだけ差し替えたい
  • 「集計カードを更新」:ダッシュボードの集計結果だけ再計算して差し替えたい

① 詳細パネルだけ再読み込み(ボタン → パネル丸ごと差し替え)

ボタン押下で、詳細パネルだけを再取得し、outerHTMLパネル要素ごと差し替えます。
(返すHTMLに同じ id を含めるのがコツです)

HTML


<div class="DEMO">

  <!-- ①:差し替え対象のパネル(初期表示は通常レンダリングでもOK) -->
  <section id="DEMO_DETAIL_PANEL" class="PANEL" aria-label="詳細パネル">
    <h4>ユーザー詳細</h4>
    <p><strong>ID:</strong>42</p>
    <p><strong>最終更新:</strong>2025-12-30 18:00</p>
    <p><strong>メモ:</strong>…</p>
  </section>

  <!--
    このボタンを押すと、詳細パネルだけを再読み込みします。
    hx-get          : 取りに行くURL(HTML断片が返る)
    hx-target       : 差し替える先(#DETAIL_PANEL)
    hx-swap         : outerHTML=箱ごと差し替える
    hx-indicator    : 通信中だけ表示する要素(ローディング)
    hx-disabled-elt : 通信中だけボタンをdisabled(連打防止)
  -->
  <button
    type="button"
    class="BTN"
    hx-get="/htmx/demo/_detail_panel.php?id=123"
    hx-target="#DEMO_DETAIL_PANEL"
    hx-swap="outerHTML"
    hx-indicator="#DETAIL_PANEL_LOADING"
    hx-disabled-elt="this"
  >
    詳細パネルを再読み込み
  </button>

  <!-- 通信中だけ出したい表示(CSSで .htmx-request を使う) -->
  <span id="DETAIL_PANEL_LOADING" class="LOADING" aria-live="polite">
    更新中…
  </span>

</div>

PHP

<?php
// ① 詳細パネル断片(outerHTMLで丸ごと差し替え)

// 型のミスを減らして堅くする(任意だけどおすすめ)
declare(strict_types=1);

// 返すのはHTML断片
header('Content-Type: text/html; charset=UTF-8');

// GETパラメータ id を整数に(無ければ0)
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// 本来はDBから最新を取得する想定(ここでは例として固定)
$data = [
  // 表示用ID
  'id'         => $id,

  // 例:いまの時刻を最終更新として表示
  'updated_at' => date('Y-m-d H:i:s'),

  // 例文
  'memo'       => 'サーバー側で再取得した最新データです(例)',
];
?>

<!-- outerHTMLで差し替えるので、同じ id="DETAIL_PANEL" を返すのがコツ -->
<section id="DEMO_DETAIL_PANEL" class="PANEL" aria-label="詳細パネル">
  <h4>ユーザー詳細</h4>

  <p>
    <strong>ID:</strong>
    <!-- XSS対策:表示前に必ずエスケープ -->
    <?= htmlspecialchars((string)$data['id'], ENT_QUOTES, 'UTF-8') ?>
  </p>

  <p>
    <strong>最終更新:</strong>
    <!-- XSS対策 -->
    <?= htmlspecialchars($data['updated_at'], ENT_QUOTES, 'UTF-8') ?>
  </p>

  <p>
    <strong>メモ:</strong>
    <!-- XSS対策 -->
    <?= htmlspecialchars($data['memo'], ENT_QUOTES, 'UTF-8') ?>
  </p>
</section>

デモ

ユーザー詳細

ID:42

最終更新:2025-12-30 18:00

メモ:

更新中…

解説

  • hx-swap="outerHTML" は「箱ごと差し替え」なので、パネルの構造(見出しや属性)も含めて一括更新できます。
  • 返す断片に id="DETAIL_PANEL" を含めているのは、次回の差し替え先がブレないようにするためです。
  • hx-indicatorhx-disabled-elt をセットにすると、通信中に「待ってね」が伝わり、連打事故も防げます。

コツ:詳細パネルのような「まとまりのあるUI」は outerHTML 更新にすると、設計がシンプルで保守しやすくなります。

② 承認ステータスだけ更新(ボタン → バッジだけ差し替え)

差し替え対象が小さいほど、htmxの気持ちよさが出ます。
ここでは「承認」ボタンで、ステータスバッジだけ差し替えます。

HTML


<div class="DEMO">

  <p>
    <!-- 表示ラベル -->
    ステータス:

    <!-- 差し替え対象:このバッジだけ更新したい -->
    <span id="APPROVAL_BADGE" class="BADGE is-pending">
      未承認
    </span>

    <!-- 通信中だけ出したい表示 -->
    <span id="APPROVAL_LOADING" class="LOADING" aria-live="polite">
      更新中…
    </span>
  </p>

  <!--
    ②:更新ボタン(承認にする)

    hx-post         : 更新先(HTML断片を返す)
    hx-target       : 差し替える先(#APPROVAL_BADGE)
    hx-swap         : outerHTML=バッジ要素ごと差し替える(classも更新しやすい)
    hx-indicator    : 通信中表示
    hx-disabled-elt : 連打防止
  -->
  <button
    type="button"
    class="BTN"
    hx-post="/htmx/demo/_approval_badge.php?id=42"
    hx-target="#APPROVAL_BADGE"
    hx-swap="outerHTML"
    hx-indicator="#APPROVAL_LOADING"
    hx-disabled-elt="this"
  >
    承認にする
  </button>

</div>

PHP

<?php
// ② 承認バッジ断片(outerHTMLで差し替え)

// 任意:型を堅くする
declare(strict_types=1);

// HTML断片を返す
header('Content-Type: text/html; charset=UTF-8');

// 更新対象ID(例)
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// 本来はここでDBを更新する想定(例)
// updateApproval($id, true);
?>

<!-- hx-target="#APPROVAL_BADGE" に対して outerHTML で差し替える -->
<span id="APPROVAL_BADGE" class="BADGE is-approved">
  承認済み
</span>

デモ

ステータス: 未承認 更新中…

解説

  • 差し替え対象が小さいので、hx-target="#APPROVAL_BADGE" でバッジにピンポイントで当てています。
  • outerHTML だと、テキストだけでなく class(色) も含めて差し替えできるため、状態表現が楽になります。
  • 更新処理はサーバー側(DB更新など)に寄せ、返すのは「更新後のバッジHTML」にするのが、htmxらしい設計です。

コツ:ステータス・チップ・ラベルなど「小さい部品」は、targetを狭くして“気持ちいい部分更新”を作ると効果的です。

③ 集計カードを更新(ボタン → カード群だけ差し替え)

ダッシュボードの「カード群」など、複数要素をまとめて更新したい場合は、
カードの入れ物(wrap)に対して innerHTML 差し替えにするとシンプルです。

HTML


<div class="DEMO">

  <!-- ③:差し替え対象(カード群の入れ物) -->
  <div id="CARD_WRAP" class="CARD_WRAP">
    <div class="CARD"><strong>未処理</strong><span>12</span></div>
    <div class="CARD"><strong>承認待ち</strong><span>5</span></div>
    <div class="CARD"><strong>本日完了</strong><span>3</span></div>
  </div>

  <!--
    ③:集計カード群を更新するボタン

    hx-get          : 集計カード群(HTML断片)を返すURL
    hx-target       : 差し替える先(#CARD_WRAP)
    hx-swap         : innerHTML=入れ物の中身だけ差し替える(箱は残す)
    hx-indicator    : 通信中表示
    hx-disabled-elt : 連打防止
  -->
  <button
    type="button"
    class="BTN"
    hx-get="/htmx/demo/_summary_cards.php"
    hx-target="#CARD_WRAP"
    hx-swap="innerHTML"
    hx-indicator="#SUMMARY_LOADING"
    hx-disabled-elt="this"
  >
    集計カードを更新
  </button>

  <!-- 通信中だけ出したい表示 -->
  <span id="SUMMARY_LOADING" class="LOADING" aria-live="polite">
    更新中…
  </span>

</div>

PHP

<?php
// ③ 集計カード群断片(innerHTMLで差し替え)
// - CARD_WRAP の中に入る「カードたち」だけを返す

// 任意:堅くする
declare(strict_types=1);

// HTML断片を返す
header('Content-Type: text/html; charset=UTF-8');

// 本来はDBや集計処理で値を作る想定(ここでは例)
$cards = [
  // カード1
  ['label' => '未処理',   'value' => random_int(0, 20)],

  // カード2
  ['label' => '承認待ち', 'value' => random_int(0, 20)],

  // カード3
  ['label' => '本日完了', 'value' => random_int(0, 20)],
];

// カード配列を順番にHTMLとして出力する
foreach ($cards as $c) {

  // 表示ラベル(XSS対策)
  $label = htmlspecialchars($c['label'], ENT_QUOTES, 'UTF-8');

  // 数値も文字列としてエスケープ(XSS対策)
  $value = htmlspecialchars((string)$c['value'], ENT_QUOTES, 'UTF-8');

  // カード開始
  echo '<div class="CARD">';

  // 左側:ラベル
  echo '<strong>' . $label . '</strong>';

  // 右側:値
  echo '<span>' . $value . '</span>';

  // カード終了
  echo '</div>';
}

デモ

未処理12
承認待ち5
本日完了3
更新中…

解説

  • hx-swap="innerHTML" は「入れ物は残して中身だけ差し替え」なので、カード群の更新に向きます。
  • サーバーは CARD_WRAP の中に入るカードHTMLだけを返す設計にすると、責務が明確になって保守しやすいです。
  • 集計処理は重くなりがちなので、必要なときだけ更新する(ボタン更新)は業務UIで扱いやすいパターンです。

コツ:複数カードをまとめて更新するなら「wrapは固定・中身だけ返す」にすると、差し替えが単純になります。

このページの著者

もちもちみかん(システムエンジニア)

社内SEとしてグループ企業向けの業務アプリを要件定義〜運用まで一気通貫で担当しています。

経験:Webアプリ/業務システム

得意:PHP・JavaScript・MySQL・CSS

個人実績:フォーム生成基盤クイズ学習プラットフォーム

詳しいプロフィールはこちら!  もちもちみかんのプロフィール

もちもちみかん0系くん
TOPへ

もちもちみかん.comとは


このサイトでは、コーディングがめんどうくさい人向けのお助けツールとして、フォームやCSSをノーコードで生成できる、
 もちもちみかん.forms
 もちもちみかん.css1
 もちもちみかん.css2
と言ったジェネレーターを用意してます。

また、このサイトを通じて、「もちもちみかん」のかわいさを普及したいとかんがえてます!