コンテンツにスキップ

フィールドエラー

field-errors は、htmx 越しのサーバサイドバリデーションエラーの ためのキットの契約です。サーバは失敗した送信(通常 422)に、問題の フィールドを名指しする小さなアラートフラグメントで答えます。 installFieldErrors() ビヘイビアが各エラーを一致するフィールドへ 振り分け — メッセージはフィールドのエラースロットへ、コントロールには aria-invalid + aria-describedby — ユーザーが直すたびにクリア します。フラグメントはドキュメント化されたワイヤ形式なので、 テンプレートエンジンやコードジェネレーターはそのまま出力できます。

別名: サーバーバリデーション表示、インラインエラー。

メールを空のまま送信すると required エラーが、taken@example.com を 使うと duplicate の項目がフィールドへ振り分けられます(メッセージ、 aria-invalid、フォーカス)。それ以外のメールは成功します: サーバは エラーをクリアする空ボディと HX-Trigger トーストで応答します。 エンドポイントは下記サーバ契約のデモ実装で、api/recipes/field-errors/ 配下に置かれています(実際のアプリでは /members など自前の URL を 使います)。

We never share it.

サーバが返す正準の形はこれです。htmx がフォーム内(またはフォームを 指す)コンテナへスワップします:

<div class="hc-alert" data-variant="error" role="alert" data-hc-field-errors>
<p class="hc-alert__title">Please fix the errors below.</p>
<ul class="hc-alert__errors">
<li class="hc-alert__error" data-field="email" data-code="duplicate"
data-message-key="members.email.duplicate">email: duplicate</li>
</ul>
<p class="hc-alert__body">optional hint line</p>
</div>
  • data-hc-field-errors がビヘイビアのオプトインです。空なら 最寄りの <form> へ振り分け。値があればフォームを指す CSS セレクタ (out-of-band スワップや、フォーム外に描画されるアラート用)。
  • data-field がコントロール(その name 属性)を名指しします。 ラジオ / チェックボックスグループは共有フィールドに解決され、隠し input はスキップされます — 真偽値フィールドのイディオム (同名の 隠し false + チェックボックス true)は見える チェックボックスに配線されます。既知のコントロールを名指ししない 項目はサマリーに見えたまま残ります — フォームレベルのエラーに 使ってください。
  • data-message-key は任意のクライアントサイドローカライズ (後述)。項目のテキストがフォールバックです。data-code は スタイリングやテストのためにそのまま通されます。

タイトルと項目のテキストはアプリが選ぶコピーです — 言い回しは UI コピーの書き方を 参照してください。

Simulate 422 をクリックすると、まさに上のフラグメントがフォームの 隣に挿入されます(htmx スワップの代役)。email のエラーは完全な ARIA 配線つきでフィールドのインラインに着地し、未知フィールドの項目は サマリーに残ります。email フィールドを編集するとエラーがクリアされ ます。

We never share it.

  1. htmx がフラグメントをスワップし、ビヘイビアが htmx:afterSwap / htmx:oobAfterSwap に反応します (MutationObserver フォールバックと、フルページのエラー描画向けの インストール時スキャンつき)。
  2. フォーム内の以前のサーバエラーがクリアされます。
  3. コントロールに一致する各 .hc-alert__error[data-field] は、 メッセージをフィールドの .hc-field__error(自動作成 — hc-field ラッパーのない素のコントロールの後にも)へ書き込み、 コントロールに aria-invalid="true"aria-describedby、 フィールドに data-invalid="true" を設定し、 data-distributed="true" の印が付きます(二重に読まれないよう サマリーでは非表示)。
  4. アラートに data-distributed="all | partial | none" が刻印され、 最初の無効なコントロールにフォーカスが移ります。
  5. フィールドのサーバエラーは、そのフィールドでの最初の input/change、submit / reset、および次のフラグメントの振り分け 前にクリアされます。
属性対象意味
data-hc-field-errorsアラートオプトイン。空 = closest('form')、値 = フォームを指す CSS セレクタ。
data-field項目エラーを付けるコントロールの name
data-code項目任意の機械可読コード(リゾルバから {code} として利用可)。
data-message-key項目任意の i18n カタログキー。項目テキストがフォールバック。
data-message-params項目カタログ検索の補間値の JSON オブジェクト(任意)。暗黙の {field}/{code} の上にマージ。不正な JSON は無視。
data-summary="auto"アラートすべての項目が振り分けられたらアラート全体を隠す。
data-focus="none"アラート最初の無効なコントロールへフォーカスしない。

メッセージキーのローカライズ

Section titled “メッセージキーのローカライズ”

data-message-key は、他のすべてのキット文字列と同じ i18n カタログで解決され ます — 起動時に一度設定してください:

import { setMessages } from '@hypermedia-components/core';
setMessages({
'members.email.duplicate': 'このメールアドレスは既に登録されています',
// `{field}` / `{code}` interpolate if you want generic messages:
'errors.required': '{field} is required',
});

翻訳が {field}/{code} 以外の値 — 制約パラメータ、バリデーション行の カラム — を必要とするときは、サーバが data-message-params に JSON オブジェクトとして送り、クライアントのリゾルバが補間パラメータへ マージします(項目の値が暗黙のものに勝ちます):

<li class="hc-alert__error" data-field="qty" data-code="stock"
data-message-key="orders.qty.exceeds"
data-message-params='{"stock": 5}'>在庫 5 を超えています。</li>
setMessages({ 'orders.qty.exceeds': '在庫 {stock} を超えています。' });

カタログにないキーは項目自身のテキストへフォールバックします — サーバが ローカライズを始めたら、最終テキストを出力してキーを落とせばよく、 クライアント側は何も変わりません。不正な data-message-params JSON も 同様に無視され、項目テキストがそのまま描画されます。

htmx ≥ 2 はデフォルトで非 2xx をスワップしません。一度だけグローバルに 422 のスワップを許可します:

document.body.addEventListener('htmx:beforeSwap', (event) => {
if (event.detail.xhr.status === 422) {
event.detail.shouldSwap = true;
event.detail.isError = false;
}
});

代わりにフラグメントを 200 で返しても構いません — クライアント側の 設定が一切要らない唯一の選択肢です。HX-Retarget: #form-errors + HX-Reswap: innerHTML はフラグメントの行き先と方法を操縦するだけで、 htmx ≥ 2 ではスワップを許可しません。これらを付けた 422 にも上の許可 (もしくは htmx.config.responseHandling のルール)が必要です。

クライアントサイドバリデーションとの関係

Section titled “クライアントサイドバリデーションとの関係”

installValidation()は、 ネイティブ制約エラーを同じ .hc-field__error スロットへ、同じ ARIA 配線で表出させます。両者は合成します: 同じコントロール上では ネイティブメッセージがサーバエラーより優先され(現在の値を反映して いるため)、どちらも相手の状態を早まってクリアしません。

  • サマリーは role="alert" を使うため、スワップ自体が読み上げられ ます。フィールドメッセージは aria-live="polite" で、コントロール から aria-describedby で参照されます。
  • 最初の無効なコントロールにフォーカスが移ります — 送信後エラーの 標準パターンです。フローが自前でフォーカスを管理するなら data-focus="none" で無効化してください。
  • 振り分けられた項目はサマリーから視覚的に除かれるだけです。どの フィールドにも一致しない項目は見えたまま残るため、エラーが静かに 落ちることはありません。

プログレッシブエンハンスメント

Section titled “プログレッシブエンハンスメント”
  • JavaScript なし(フルページ再描画)では、アラートがすべてのエラーを 素のリストとして描画します — 振り分けはエンハンスメントで、何も 失われません。
  • htmx なしでも、初期 HTML に存在するフラグメントはインストール時 スキャンによって振り分けられます。
  • フィールド — エラーが 着地するラベル / コントロール / メッセージの合成。
  • アラート — サマリーの コンテナ。
  • データ領域 — フォーム以外のコンテンツ向けの、スワップ駆動の対応物。