結論
フォームのUIをAIに安定して作らせたいなら、項目の定義・バリデーションの内容とタイミング・エラー表示の見せ方・送信中の状態の4つをプロンプトに書き込んでください。フォームはデータテーブルと違って「状態」が多いUIです。入力前・入力中・エラー中・送信中・送信完了と画面が切り替わるため、そこを指定しないとAIが毎回違う挙動で埋めます。「登録フォームを作って」だけだと、必須チェックの粒度や、エラーをいつ・どこに出すかがそのつど変わり、後から直すことになります。
この記事では、実際に「雑な指示」と「整えた指示」の両方をAIに投げて、生成結果がどう変わったかを載せます。整えた指示で返ってきたコードは、下のほうにそのまま動くデモとして置いています。一発で出た点と、一箇所だけ直した点も正直に書きます。
フォームは「項目・バリデーション・エラー表示・送信中状態」を書き切れば出力が安定する。状態の切り替わりを言葉にしておくのが、テーブルとの一番の違い。
雑な指示だと何が起きるか
まず、多くの人が最初に打つであろう一文を試しました。
短くて楽ですが、フォームで一番決めたい「状態」の部分をこちらが指定していません。その結果、次のズレになって返ってきました。
項目は「名前・メール・メッセージ」の3つを勝手に決定。実際に集めたい項目とは違い、電話番号や種別の選択肢は入っていませんでした。
バリデーションは送信ボタンを押した瞬間にまとめてalertで出す実装。どの項目が悪いかは分からず、入力中のチェックもありませんでした。
送信すると alert('送信しました') が出るだけ。ボタンの二度押し防止も、送信中の表示も、完了後の画面もなしでした。
どれも「間違い」ではありません。指定していないのだから、AIが埋めた仮定に過ぎません。問題は、フォームは状態の切り替わりが本体なのに、その部分をまるごとAI任せにしている点です。結局「項目はこれで」「エラーは項目の下に出して」「送信中はボタンを無効にして」と追加でやり取りが増え、往復するうちに最初から書いておいたほうが速かった、となります。
整えた指示:実プロンプト全文
そこで、AIに仮定させる余地を減らしたプロンプトを書きました。これがそのまま使える全文です。ポイントは、項目を表で渡すこと、バリデーションの内容とタイミングを分けて書くこと、エラー表示の場所を指定すること、そして送信中と送信完了の状態まで書くことです。
次の仕様で問い合わせフォームのUIを作ってください。 【出力形式】 - HTML/CSS/JavaScript を 1つの HTML ファイルにまとめる - フレームワークやライブラリは使わない(バニラJSのみ、CDN読み込みも不可) - コードはコピペでそのまま動く完成形にする 【入力項目】 | キー | ラベル | 種類 | 必須 | バリデーション | |----------|-------------|-----------|-----|-------------------------------------| | name | お名前 | text | 必須 | 1文字以上 | | email | メールアドレス | email | 必須 | メール形式(@とドメインを含む) | | category | お問い合わせ種別 | select | 必須 | 「選択してください」以外を選ぶ | | tel | 電話番号 | tel | 任意 | 入力時のみ、数字とハイフンのみ | | message | お問い合わせ内容 | textarea | 必須 | 10文字以上・500文字以内 | - category の選択肢は「製品について」「お見積り」「その他」 【バリデーションのタイミング】 - 初回は「送信」ボタンを押したときに全項目を検証する - 一度エラーになった項目は、その後は入力するたびに(blur ではなく input で)再検証する - エラーが1つでもあれば送信せず、最初のエラー項目にフォーカスを移す 【エラーの見せ方】 - エラーメッセージは各項目の入力欄の直下に赤字で出す - エラー中の入力欄は枠線を赤くする - alert は使わない 【送信中・送信完了の状態】 - 送信ボタンを押して検証を通過したら、ボタンを無効化しラベルを「送信中…」に変える - 実際の通信はせず、1秒後に送信完了とみなす - 完了したらフォームの下に緑色で「送信しました」の完了メッセージを出す 各処理が何をしているかのコメントを日本語で入れてください。
雑な指示との一番の違いは、項目を表(テーブル)で渡しているところと、「タイミング」を独立した見出しで書いているところです。項目定義を表で渡すやり方は、Excelやスプレッドシートで仕様をまとめる文化に馴染んだ人ほど書きやすく、AIも「キー・ラベル・種類・必須・バリデーション」の対応を取り違えにくくなります。CSVやExcelの項目一覧をそのまま貼り付けても通じるので、Excelのコピペをフォームに取り込む記事で扱ったような、既存の項目表を持っている人はそれを流用できます。
生成結果:動くデモ
上のプロンプトで返ってきたコードを、そのままこのページに埋め込んだものが下です。空のまま送信するとエラーが項目の下に出て、一度エラーになった項目は入力するたびに再検証されます。すべて正しく埋めて送信すると、ボタンが「送信中…」に変わり、1秒後に完了メッセージが出ます。
送信完了後にフォームを reset() したときエラー表示が残ってしまう箇所だけ、一箇所手を入れました。それ以外の検証ロジック・エラーの出し分け・再検証のタイミング・送信中のボタン制御は、上のプロンプト一発で返ってきたものをそのまま使っています。
一発で出た点と、直した点
一次情報として、実際にどこまで一発で出て、どこを直したかを書きます。
一発で出た:再検証のタイミングと送信中の状態
「一度エラーになった項目だけ input のたびに再検証する」という、フォームで一番仕様が伝わりにくい挙動が最初から正しく出ました。エラー項目を記録する変数を持ち、そこに入っている項目だけ再検証する実装になっていて、こちらの意図どおりでした。送信ボタンの無効化と「送信中…」への切り替え、1秒後の完了表示も、仕様に書いたとおりに動きました。ここは雑な指示だと必ず抜ける部分です。
直した:送信後の reset でエラー表示が残る
送信完了後に form.reset() で入力値は消えるものの、赤枠とエラーメッセージの表示が残っていました。reset() は値を初期化するだけで、こちらが付けたクラスやテキストまでは消さないためです。完了処理の中で各項目のエラー表示を掃除するコードを足しました。これは仕様に「送信後は表示もリセットする」と書き漏らした自分側の不足で、プロンプトに一行足せば防げた部分です。
データテーブルのときと同じく、直しが発生したのは「AIが間違えた」のではなく「こちらが書き忘れた」ものでした。状態の切り替わりを言葉にして渡すほど、手直しは減ります。
フォームのプロンプトで効く4つの指定
今回の比較で効果がはっきり出た指定を、他のフォームにも流用できる形でまとめます。
項目を表で渡す(キー・ラベル・種類・必須・バリデーション)
項目定義は箇条書きより表で渡すほうが取り違えが減ります。とくに「必須/任意」と「バリデーション」を列で分けておくと、任意項目を必須にしてしまうような定番のズレを防げます。手元にCSVやExcelの項目一覧があるなら、それを貼るだけで通じます。
バリデーションの「タイミング」を内容と分けて書く
フォームで一番ブレるのは、何を検証するかではなく「いつ検証するか」です。「送信時に全項目、エラー後はその項目だけ入力のたびに」のように、初回・再検証・送信ブロックの3点をタイミングとして独立に書くと、生成結果が安定します。ここを書かないと、全項目を毎キー検証する重い実装や、逆に送信時にしか見ない実装になりがちです。
エラーの見せ方と送信中の状態を言葉にする
「エラーは入力欄の直下に赤字・alertは使わない」「送信中はボタンを無効化してラベルを変える・完了メッセージを出す」まで書きます。フォームは入力前・エラー中・送信中・完了と画面が変わるUIなので、この状態遷移を指定しておくと、二度押しや無反応といった実務で困る抜けがなくなります。
バリデーションの指定は「どこまで書くか」で迷いますが、目安はタイミングと見せ方は必ず書く、検証ルール自体は表に一行で足りるです。ルールは「メール形式」「10文字以上」程度の粒度で十分で、正規表現まで書く必要はありません。書きすぎるより、状態の切り替わりを漏らさないほうが効きます。
まとめ
フォームUIをAIに安定して作らせる鍵は、項目の定義・バリデーションの内容とタイミング・エラー表示の見せ方・送信中の状態の4つを最初に書き切ることでした。フォームはデータテーブルより「状態」が多いUIなので、雑な指示だとこの状態遷移をAIが勝手に埋め、後から直すやり取りで時間がかかります。項目を表で渡し、タイミングと見せ方を言葉にした整えた指示では、一発でほぼ完成し、手直しは送信後の表示リセット一箇所だけで済みました。
まずはこの記事のプロンプトをコピーして、項目の表を自分の集めたいデータに差し替えるところから試してみてください。動くフォームの土台やAI用プロンプトは、下の関連事例のコードからも取れます。テーブル側の書き方はデータテーブルUIをAIに作らせる記事に、生成結果がスマホで崩れる・状態が足りないなど「惜しい」出力になったときの直し方は修正プロンプトで直す記事にまとめています。