組み込みブラウザの <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}
      />
    </>
  );
}


テキストエリアの初期値を指定する

テキストエリアの初期値を任意で指定できます。defaultValue 文字列として渡します。

export default function EditPost() {
  return (
    <label>
      Edit your post:
      <textarea
        name="postContent"
        defaultValue="I really enjoyed biking yesterday!"
        rows={4}
        cols={40}
      />
    </label>
  );
}

落とし穴

HTML とは異なり、<textarea>Some content</textarea> のように初期テキストを渡すことはサポートされていません。


フォーム送信時にテキストエリアの値を読み取る

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>name を指定します。例: <textarea name="postContent" />。指定した name は、フォームデータのキーとして使用されます。例: { postContent: "Your post" }

落とし穴

デフォルトでは、<form> 内の 任意の <button> がフォームを送信します。これは驚くべきことです。Button React コンポーネントが独自にある場合は、<button> の代わりに <button type="button"> を返すことを検討してください。そして、明示的に、フォームを送信する 必要がある ボタンには <button type="submit"> を使用します。


ステート変数によるテキストエリアの制御

<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": {}
}

落とし穴

onChange なしで value を渡すと、テキストエリアに文字を入力できなくなります。 テキストエリアに value を渡して制御する場合、渡された値を常に持つように強制します。したがって、ステート変数を value として渡しても、onChange イベントハンドラでそのステート変数を同期的に更新するのを忘れると、React はキー入力ごとにテキストエリアを、指定した value に戻します。


トラブルシューティング

テキストエリアに文字を入力しても更新されません

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 はコンポーネントを非制御にするか制御するかを判断できないためです。制御されたコンポーネントは、nullundefined ではなく、常に文字列の value を受け取る必要があります。

API または状態変数から value が取得される場合、初期化時に null または undefined になっている可能性があります。その場合、最初に空の文字列 ('') に設定するか、value={someValue ?? ''} を渡して、value が文字列であることを確認してください。