sashigane
コンポーネント

Form

入力をまとめて送る。送信中の二重送信も防ぐ

バリデーションは持ちません

規則を走らせる仕組みはありません。走らせるのは利用側です。 ここが持つのは、利用側が書き忘れるものだけです。

送信に失敗したら、最初の誤りへフォーカスが移ります

長いフォームでは、誤りが画面の外にあると何が起きたのか分かりません。 送信ボタンを押しても、何も起きていないように見えます。

誤りを名乗っている欄(aria-invalid)を探すので、 どのライブラリで検証したかに依りません。

移す先は全体の誤り → 最初の誤りの欄の順です。全体の誤りは 「なぜ送れなかったか」を説明していて、フォームの上端にあります。 そこへ移せば、下へ読み進める形になります。

検証が非同期なら、Promise を返してください

いつ誤りが付くかは、送信処理が終わるまで分かりません。 Promise を返せば、その解決を待ちます——async で書けばそうなります。

<Form onSubmit={async (event) => {
  event.preventDefault();
  await validate();   // Promise を返すので、待てます
}}>

返さずに非同期の検証を始めた場合、フォーカスは移りません。 待ち続ける形にはしていません——いつやめるかを決められず、 時間が経ってからフォーカスを奪うのは、移さないより悪いからです。 そのころ利用者は別の場所を触っています。

フォーカスを持てないものが名前を持つこともあります(ラジオのグループは fieldset が名前を持ち、 fieldset にフォーカスは乗りません)。そのときは中の最初の入力へ移します。

動かしたくないときは focusOnError={false} を渡してください。

ブラウザ標準の検証は無効にしてあります

既定の吹き出しは Field が出す文言と二重になり、見た目も位置も揃いません。 片方は読み上げに届きません。

使えなくしたわけではありません。 noValidate={false} を渡せば標準の検証に戻ります。 required 自体は残るので、読み上げには届きます。

フォーム全体の誤りを出すとき

欄1つの誤りではないもの——送信そのものが失敗したときや、 複数の欄の組み合わせが成り立たないときに使います。

指す先がありません。 どの欄が悪いとも言えないので aria-describedby では結べず、 その場で読み上げに届く形(role="alert")で出しています。

3つの状態

通常・空・エッジケースの3つは、どのコンポーネントにも必ずあります。

通常default.tsx

通常。入力をまとめて、操作を並べる。

返信に使います

空empty.tsx

空。欄が1つも無い。

エッジケースedge.tsx

エッジケース。フォーム全体の誤りと、欄の誤りが同時にある。

入力してください

props

Prop

Type

型と説明はコンポーネントのソースから抽出しています。既定値は出していません——cva の defaultVariants は 署名に現れないので、表に出すと「引数のデフォルトが書かれているものだけ」になり、嘘になります。

On this page