<textarea>
ブラウザ組み込みの <textarea> コンポーネント を利用することで、複数行のテキスト入力エリアをレンダーすることができます。
<textarea />リファレンス
<textarea>
テキストエリアを表示するためには、ブラウザ組み込みの <textarea> コンポーネントをレンダーします。
<textarea name="postContent" />props
<textarea> は一般的な要素の props をすべてサポートしています。
value プロパティを渡すことで、テキストエリアを制御されたコンポーネント (controlled component) にできます。
value: 文字列。テキストエリア内のテキストを制御します。
value を渡す場合は、渡された値を更新する onChange ハンドラも渡す必要があります。
もし <textarea> を非制御コンポーネント (uncontrolled component) として使用する場合は、代わりに defaultValue プロパティを渡すことができます。
defaultValue: 文字列。テキストエリアの初期値を指定します。
これらの <textarea> の props は、非制御のテキストエリアと制御されたテキストエリアの両方で用いられます。
autoComplete:'on'または'off'。オートコンプリートの挙動を指定します。autoFocus: ブーリアン。trueの場合、React はマウント時にこの要素にフォーカスします。children:<textarea>には子要素を指定できません。初期値を設定するには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を使用してください。- テキストエリアが props として文字列型の
valueを受け取ると、制御されたテキストエリアとして扱われます。 - テキストエリアは制御されたコンポーネントと非制御コンポーネントに同時になることはできません。。
- テキストエリアは、ライフタイム中に制御されたコンポーネントから非制御コンポーネント、またはその逆に切り替えることはできません。
- すべての制御されたテキストエリアには、制御に使っている state を同期的に更新するための
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> タグ内に配置します。これにより、ブラウザに対してこのラベルがそのテキストエリアに関連付けられていることが伝わります。ユーザがラベルをクリックすると、ブラウザは自動的にテキストエリアにフォーカスします。これはアクセシビリティの観点からも重要です。ユーザがテキストエリアにフォーカスすると、スクリーンリーダがラベルのキャプションを読み上げます。
もし <label> 内に <textarea> をネストできない場合は、同じ ID を <textarea id> と <label htmlFor> に渡すことで関連付けることができます。同一コンポーネントの複数のインスタンス間での競合を避けるために、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> ); }
フォーム送信時にテキストエリアから値を読み取る
テキストエリアを <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> ); }
state 変数を使ってテキストエリアを制御する
<textarea /> のようなテキストエリアは非制御です。たとえ <textarea defaultValue="Initial text" /> のようにデフォルト値を指定している場合でも、この JSX で指定しているのはあくまで初期値であって現在の値ではありません。
制御されたテキストエリアをレンダーするには、value プロパティを渡してください。React はテキストエリアが常に渡した value を反映するようにします。通常、state 変数を宣言することでテキストエリアを制御します。
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 の一部を再レンダーしたい場合に便利です。
import { useState } from 'react'; import MarkdownPreview from './MarkdownPreview.js'; export default function MarkdownEditor() { const [postContent, setPostContent] = useState('_Hello,_ **Markdown**!'); return ( <> <label> Enter some markdown: <textarea value={postContent} onChange={e => setPostContent(e.target.value)} /> </label> <hr /> <MarkdownPreview markdown={postContent} /> </> ); }
トラブルシューティング
テキストエリアにタイプしても内容が更新されない
value があるが onChange のないテキストエリアをレンダーすると、コンソールにエラーが表示されます。
// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly.エラーメッセージが示すように、初期値を指定したいだけの場合は、代わりに defaultValue を渡すようにしてください。
// ✅ Good: uncontrolled text area with an initial value
<textarea defaultValue={something} />state 変数でこのテキストエリアを制御したい場合は、onChange ハンドラを指定してください。
// ✅ Good: controlled text area with onChange
<textarea value={something} onChange={e => setSomething(e.target.value)} />値を意図的に読み取り専用にしたい場合は、エラーを抑制するために props として readOnly を追加してください。
// ✅ Good: readonly controlled text area without on change
<textarea value={something} readOnly={true} />キーストロークごとにテキストエリアのカーソルが先頭に戻る
テキストエリアを制御する場合、onChange 中でその state 変数を DOM からやってくるテキストエリアの値に更新する必要があります。
state を 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);
}コードを修正するには、state を e.target.value の値に同期的に更新します。
function handleChange(e) {
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}これで問題が解決しない場合、テキストエリアがキーストロークごとに DOM から削除・再追加されている可能性があります。これは、再レンダーごとに state を誤ってリセットしている場合に起こります。例えば、テキストエリアまたはその親が常に異なる key 属性を受け取っている可能性や、コンポーネント定義をネストしている(これは React では許されておらず、「内側」のコンポーネントがレンダー時に再マウントさえることになります)可能性があります。
“A component is changing an uncontrolled input to be controlled” というエラーが発生する
コンポーネントに value を渡す場合、そのライフサイクル全体を通じて文字列型でなければなりません。
最初に value={undefined} を渡しておき、後で value="some string" を渡すようなことはできません。なぜなら、React はあなたがコンポーネントを非制御コンポーネントと制御されたコンポーネントのどちらにしたいのか分からなくなるからです。制御されたコンポーネントは常に文字列の value を受け取るべきであり、null や undefined であってはいけません。
あなたの value が API や state 変数から来ている場合、それが null や undefined に初期化されているかもしれません。その場合、まず空の文字列('')にセットするか、value が文字列であることを保証するために value={someValue ?? ''} を渡すようにしてください。