組み込みブラウザの <textarea>
コンポーネントを使用すると、複数行のテキスト入力をレンダリングできます。
<textarea />
リファレンス
<textarea>
テキストエリアを表示するには、組み込みブラウザの <textarea>
コンポーネントをレンダリングします。
<textarea name="postContent" />
プロパティ
<textarea>
は、共通の要素プロパティをすべてサポートします。
value
プロパティを渡すことで、テキストエリアを制御することができます。
value
: 文字列。テキストエリア内のテキストを制御します。
value
を渡す場合は、渡された値を更新するonChange
ハンドラーも渡す必要があります。
もしあなたの<textarea>
が制御されていない場合は、代わりにdefaultValue
プロパティを渡すことができます。
defaultValue
: 文字列。テキストエリアの初期値を指定します。
これらの<textarea>
プロパティは、制御されていないテキストエリアと制御されたテキストエリアの両方に関連します。
autoComplete
:'on'
または'off'
のいずれか。オートコンプリートの動作を指定します。autoFocus
: ブール値。true
の場合、Reactはマウント時に要素にフォーカスします。children
:<textarea>
はchildrenを受け入れません。初期値を設定するには、defaultValue
を使用してください。cols
: 数値。平均文字幅でのデフォルトの幅を指定します。デフォルトは20
です。disabled
: ブール値です。true
の場合、入力はインタラクティブではなくなり、暗く表示されます。form
: 文字列です。この入力が属する<form>
のid
を指定します。省略した場合、最も近い親フォームが対象となります。maxLength
: 数値です。テキストの最大長を指定します。minLength
: 数値です。テキストの最小長を指定します。name
: 文字列です。フォームとともに送信されるこの入力の名前を指定します。フォーム送信時にテキストエリアの値を読み取るを参照してください。onChange
:Event
ハンドラー関数です。ステート変数でテキストエリアを制御する場合に必須です。ユーザーが入力値を変更したときに直ちに発火します(例えば、すべてのキーストロークで発火します)。ブラウザのinput
イベントのように動作します。onChangeCapture
: キャプチャフェーズで発火するonChange
のバージョンです。onInput
:Event
ハンドラー関数です。ユーザーによって値が変更されたときに直ちに発火します。歴史的な理由から、Reactでは同様に動作するonChange
を使用するのが慣例となっています。onInputCapture
: キャプチャフェーズで発火するonInput
のバージョンです。onInvalid
:Event
ハンドラー関数です。フォーム送信時に入力が検証に失敗した場合に発火します。組み込みのinvalid
イベントとは異なり、ReactのonInvalid
イベントはバブリングします。onInvalidCapture
: キャプチャフェーズで発火するonInvalid
のバージョンです。onSelect
:Event
ハンドラー関数です。<textarea>
内の選択範囲が変更された後に発火します。ReactはonSelect
イベントを拡張し、空の選択や編集時(選択範囲に影響を与える可能性がある)にも発火するようにしました。onSelectCapture
: キャプチャフェーズで発火するonSelect
のバージョンです。placeholder
: 文字列です。テキストエリアの値が空の場合に、グレー表示で表示されます。readOnly
: ブール値です。true
の場合、テキストエリアはユーザーによる編集ができません。required
: ブール値です。true
の場合、フォームを送信するためには値を指定する必要があります。rows
: 数値です。平均的な文字の高さでデフォルトの高さを指定します。デフォルトは2
です。wrap
:'hard'
、'soft'
、または'off'
のいずれかです。フォームを送信する際のテキストの折り返し方法を指定します。
注意点
<textarea>something</textarea>
のように子要素を渡すことは許可されていません。初期コンテンツにはdefaultValue
を使用してください。- テキストエリアが文字列の
value
プロパティを受け取ると、制御されたコンポーネントとして扱われます。 - テキストエリアは、制御された状態と制御されていない状態の両方を同時に持つことはできません。
- テキストエリアは、そのライフサイクル中に制御された状態と制御されていない状態を切り替えることはできません。
- すべての制御されたテキストエリアには、そのバッキング値を同期的に更新する
onChange
イベントハンドラーが必要です。
使用方法
テキストエリアの表示
テキストエリアを表示するには、<textarea>
をレンダリングします。デフォルトのサイズは、rows
属性と cols
属性で指定できますが、デフォルトではユーザーがサイズを変更できます。サイズ変更を無効にするには、CSS で resize: none
を指定できます。
export default function NewPost() { return ( <label> Write your post: <textarea name="postContent" rows={4} cols={40} /> </label> ); }
テキストエリアにラベルを付ける
通常、すべての <textarea>
を <label>
タグ内に配置します。これにより、このラベルがそのテキストエリアに関連付けられていることがブラウザに伝えられます。ユーザーがラベルをクリックすると、ブラウザはテキストエリアにフォーカスします。これはアクセシビリティにとっても重要です。スクリーンリーダーは、ユーザーがテキストエリアにフォーカスすると、ラベルのキャプションをアナウンスします。
<textarea>
を <label>
にネストできない場合は、<textarea id>
と <label htmlFor>
に同じ ID を渡して関連付けます。1 つのコンポーネントのインスタンス間の競合を避けるために、useId
を使用してこのような ID を生成します。
import { useId } from 'react'; export default function Form() { const postTextAreaId = useId(); return ( <> <label htmlFor={postTextAreaId}> Write your post: </label> <textarea id={postTextAreaId} name="postContent" rows={4} cols={40} /> </> ); }
export default function EditPost() { return ( <label> Edit your post: <textarea name="postContent" defaultValue="I really enjoyed biking yesterday!" rows={4} cols={40} /> </label> ); }
フォーム送信時にテキストエリアの値を読み取る
textarea の周囲に <form>
を追加し、内部に <button type="submit">
を追加します。これにより、<form onSubmit>
イベントハンドラーが呼び出されます。デフォルトでは、ブラウザはフォームデータを現在の URL に送信し、ページを更新します。この動作をオーバーライドするには、e.preventDefault()
を呼び出します。フォームデータは new FormData(e.target)
で読み取ります。
export default function EditPost() { function handleSubmit(e) { // Prevent the browser from reloading the page e.preventDefault(); // Read the form data const form = e.target; const formData = new FormData(form); // You can pass formData as a fetch body directly: fetch('/some-api', { method: form.method, body: formData }); // Or you can work with it as a plain object: const formJson = Object.fromEntries(formData.entries()); console.log(formJson); } return ( <form method="post" onSubmit={handleSubmit}> <label> Post title: <input name="postTitle" defaultValue="Biking" /> </label> <label> Edit your post: <textarea name="postContent" defaultValue="I really enjoyed biking yesterday!" rows={4} cols={40} /> </label> <hr /> <button type="reset">Reset edits</button> <button type="submit">Save post</button> </form> ); }
ステート変数によるテキストエリアの制御
<textarea />
のようなテキストエリアは非制御です。たとえ 初期値を渡したとしても、例えば <textarea defaultValue="初期テキスト" />
のように記述しても、JSX は初期値を指定するだけで、現在の値を指定するわけではありません。
制御されたテキストエリアをレンダリングするには、value
プロパティを渡してください。React はテキストエリアに常に渡された value
を強制的に持つようにします。通常、テキストエリアを制御するには、ステート変数を宣言します。
function NewPost() {
const [postContent, setPostContent] = useState(''); // Declare a state variable...
// ...
return (
<textarea
value={postContent} // ...force the input's value to match the state variable...
onChange={e => setPostContent(e.target.value)} // ... and update the state variable on any edits!
/>
);
}
これは、キー入力のたびに UI の一部を再レンダリングしたい場合に役立ちます。
{ "dependencies": { "react": "latest", "react-dom": "latest", "react-scripts": "latest", "remarkable": "2.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "devDependencies": {} }
トラブルシューティング
テキストエリアに文字を入力しても更新されません
value
を指定してテキストエリアをレンダリングしたものの、onChange
を指定しなかった場合、コンソールにエラーが表示されます。
// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />
onChange
ハンドラがないフォームフィールドに value
プロパティを渡しました。これにより、読み取り専用フィールドとしてレンダリングされます。フィールドが可変であるべき場合は、defaultValue
を使用してください。それ以外の場合は、onChange
または readOnly
のいずれかを設定してください。エラーメッセージが示すように、初期値のみを指定したかった場合は、代わりに defaultValue
を渡してください。
// ✅ Good: uncontrolled text area with an initial value
<textarea defaultValue={something} />
ステート変数でこのテキストエリアを制御したい場合は、onChange
ハンドラを指定してください。
// ✅ Good: controlled text area with onChange
<textarea value={something} onChange={e => setSomething(e.target.value)} />
値が意図的に読み取り専用である場合は、エラーを抑制するために readOnly
プロパティを追加してください。
// ✅ Good: readonly controlled text area without on change
<textarea value={something} readOnly={true} />
テキストエリアのキャレットがキー入力ごとに先頭にジャンプします
テキストエリアを制御する場合は、onChange
中に DOM から取得したテキストエリアの値にステート変数を更新する必要があります。
e.target.value
以外のものに更新することはできません。
function handleChange(e) {
// 🔴 Bug: updating an input to something other than e.target.value
setFirstName(e.target.value.toUpperCase());
}
非同期的に更新することもできません。
function handleChange(e) {
// 🔴 Bug: updating an input asynchronously
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}
コードを修正するには、e.target.value
に同期的に更新してください。
function handleChange(e) {
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}
これで問題が解決しない場合は、キー入力ごとにテキストエリアが DOM から削除されて再追加されている可能性があります。これは、再レンダリングごとにステートを誤ってリセットしている場合に発生する可能性があります。たとえば、テキストエリアまたはその親のいずれかが常に異なる key
属性を受け取っている場合、またはコンポーネント定義をネストした場合(これは React では許可されておらず、「内部」コンポーネントがレンダリングごとに再マウントされる原因となります)に発生する可能性があります。
「コンポーネントが非制御の入力を制御された入力に変更しています」というエラーが出ています。
コンポーネントに value
を渡す場合、そのライフサイクル全体を通じて文字列である必要があります。
最初に value={undefined}
を渡し、後で value="some string"
を渡すことはできません。React はコンポーネントを非制御にするか制御するかを判断できないためです。制御されたコンポーネントは、null
や undefined
ではなく、常に文字列の value
を受け取る必要があります。
API または状態変数から value
が取得される場合、初期化時に null
または undefined
になっている可能性があります。その場合、最初に空の文字列 (''
) に設定するか、value={someValue ?? ''}
を渡して、value
が文字列であることを確認してください。