0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIエージェントに数値入力欄を実装させる

0
Last updated at Posted at 2026-08-28

AIエージェントにUIを作成してもらうときに、数値入力欄を数値形式の入力欄になってしまうことがあります。
毎回、後から修正してもらうのが面倒なので、プロンプトを用意しました。

数値形式の入力欄とは、HTMLの<input type="number">にあたります。
入力内容を同期していると、空欄や不正な文字が入力できず、入力内容が強制的に制限されることで、

  • 例えば10→5に変更したくても、5を入力する前に10を消すことができなかったり、最小値、最大値の関係で1や105にもできなかったりと使いにくくなります。
  • 少数を入力、あるいは消したいときも同様です。

そのため不正な入力自体は可能で、後から数値に変換したり、バリデーションしたものを反映する必要があります。
また、入力内容をプレビューなどに反映する機能があるアプリでは、入力中でも即時プレビューに反映された方が便利です。

次のプロンプトは普段使用しているReact向けのものです。技術スタックが異なる場合は調整してください。

プロンプト 指示文

### 数値入力欄の実装ルール

数値入力欄を実装するときは、以下のルールを必ず守ること。**`type="number"` の入力欄は使用しない**(ブラウザが空欄・"1."・"-"・範囲外などの入力をブロックしてしまい、例: 10→5 に直す際に一度消すこともできない)。

1. **入力欄はテキスト入力にする**: `type="text"`(MUI なら `<TextField>` のデフォルト)を使う。数値キーボードが必要なら `inputMode="decimal"` を付けてもよい。`type="number"` にしない。
2. **value は文字列で保持する**: state やフォーム変数は `number` ではなく `string` 型にし、実際のデータ(数値)とは分離する。初期値や対象データの変更時のみ `useEffect` 等で文字列を同期する。そのため、空欄・途中文字列・範囲外の値も入力途中はそのまま保持され、入力がブロックされない。
3. **後から数値に変換し、不正入力はユーザーに明示する**: 値を実際に使う時点で `parseFloat`(または `Number`/`parseInt`)で変換する。`Number.isNaN(parseFloat(value))` なら「無効」として実データには書き込まず、入力欄の `error` props を `true` にして赤字表示する(MUI の `<TextField error={isInvalid}>` など)。さらに `helperText` に理由(例: `isInvalid && "数値を入力してください"`)を表示し、実行ボタンは `disabled` にして確定できないようにする。不正入力を黙って無視・スルーしないこと。
4. **入力中にプレビューへ即時反映**: 変換が有効になるたびに即座に実データとプレビューを更新する(例: `triggerPreviewUpdate()`)。不正文字列の間は更新をスキップし、前の値のままに保つ。
5. **範囲制約は min/max 属性でなく数値に適用**: 最小値・最大値は `Math.max(0, val)` / `Math.min(...)` を変換後の数値へ適用する。input の `min`/`max`/`step` は設定しない(途中入力や一時的な範囲外入力を許すため)。
6. **確定時も最終的に `parseFloat` で変換した有効値のみ使う**: サーバー送信・保存の直前に再度変換し、無効値(`isNaN`)なら送信しない。

Skill.md

---
name: number-input
description: 数値入力欄、数値フィールド、数値テキストフィールド、スライダー値入力(単位付き入力、座標入力、長さ・角度・金額などの数値入力)を実装するとき、または type="number" の入力欄を見かけたときに使用。type="number" を禁止し、テキスト入力+文字列状態+parseFloat による後変換で、途中入力や範囲外入力をブロックしない実装にする
---

# 数値入力欄の実装ルール

数値入力欄を実装するときは、以下のルールを必ず守ること。**`type="number"` の入力欄は使用しない**(ブラウザが空欄・`1.``-`・範囲外などの入力をブロックしてしまい、例: 10→5 に直す際に一度消すこともできない)。

## ルール

1. **入力欄はテキスト入力にする**: `type="text"`(MUI なら `<TextField>`、React なら `<input type="text">` のデフォルト)を使う。数値キーボードが必要なら `inputMode="decimal"` を付けてもよい。`type="number"` にしない。
2. **value は文字列で保持する**: state やフォーム変数は `number` ではなく `string` 型にし、実際のデータ(数値)とは分離する。初期値や対象データの変更時のみ `useEffect` 等で文字列を同期する。これにより、空欄・途中文字列・範囲外の値も入力途中はそのまま保持され、入力がブロックされない。
3. **後から数値に変換し、不正入力はユーザーに明示する**: 値を実際に使う時点で `parseFloat`(または `Number`/`parseInt`)で変換する。`Number.isNaN(parseFloat(value))` なら「無効」として実データには書き込まず、**入力欄の `error` 属性を `true` にして一目でわかるようにする**(MUI の `<TextField error={isInvalid}>` などで赤字表示)。さらに `helperText` に理由(例: `isInvalid && "数値を入力してください"`)を表示し、実行ボタンは `disabled` にして確定できないようにする。表示色を暗い背景にしている場合は `error` 表示が十分見えることも確認する。**不正入力を黙って無視・スルーしないこと。**
4. **入力中にプレビューへ即時反映**: 変換が有効になるたびに即座に実データとプレビューを更新する(例: `triggerPreviewUpdate()`)。不正文字列の間は更新をスキップし、前の値のままに保つ。
5. **範囲制約は min/max 属性でなく数値に適用**: 最小値・最大値は `Math.max(0, val)` / `Math.min(...)` を変換後の数値へ適用する。input の `min`/`max`/`step` は設定しない(途中入力や一時的な範囲外入力を許すため)。
6. **確定時も最終的に `parseFloat` で変換した有効値のみ使う**: サーバー送信・保存の直前に再度変換し、無効値(`isNaN`)なら送信しない。

## 避けるべきパターン(旧実装の残存例)

- `type="number"` を使い、`onChange={e => model.value = Number(e.target.value)}` のように入力のたびに即時変換してモデルへ書き戻すもの。
- 実データ(number)をそのまま入力欄の `value` に直接バインドするもの。

これらのパターンは、途中状態(空、`1.``-`、範囲外)が表現できないため、10→5 の変更などが不可能になる。

正解となるアプリについて調査、説明してもらった:

このアプリの数値入力欄のデータの扱い方について説明してください。AIエージェントにUIを作成してもらうときに、毎回、数値入力欄を数値形式の入力欄にしてしまい、空欄や不正な文字が入力できず、入力内容が強制的に制限されることで、例えば10→5に変更したくても、5を入力する前に10を消すことができなかったり、最小値、最大値の関係で1や105にもできなかったりと使いにくくなります。また、少数を入力、あるいは消したいときも同様です。そのため不正な入力自体は可能で、後から数値に変換する必要があります。また、入力内容をプレビューなどに反映する機能があるアプリでは、入力中でも即時プレビューに反映された方が便利です。このアプリではそういった問題が解決されているのですが、AIエージェントに指示するための文章を作成してください。

Q. この問題は入力欄の値を同期するときだけ発生しますか?

A. いいえ、同期だけが原因ではありません。同期の有無で症状が分かれます。

  • 「10→5 にできない」「1・105 にできない」→ 同期が原因。入力欄の表示値を数値のモデルと結び、onChange で毎回 Number()/parseFloat() して書き戻す実装では、途中の状態(空、範囲外、小数の途中)がモデルと一致せず、モデル値に表示が引き戻されます。これが最初の症状の主因です。
  • 「小数や検索文字が入力できない」→ type="number" 自体が原因。ブラウザは数値でない中間入力(1.-、英字)に対し e.target.value'' にしてしまい、同期していない(ローカル文字列 state のみ)場合でも、キー入力のたびに変換→反映する実装だと途中状態が失われます。type="number" の入力欄は「どのみち文字列としての中間状態を正しく渡せない」ことが根本原因です。

つまり、入力のたびの即時変換・同期と、type="number" による文字列中間状態の破棄の2つが独立に問題を引き起こします。そのため指示文のルール(テキスト入力 + 文字列 state + 変換は使用時のみ)は、同期タイミングだけ直しても不十分で、両方必要、という意味です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?