Le composant natif <textarea> du navigateur vous permet d’afficher un champ de saisie textuelle multiligne.

<textarea />

Référence

<textarea>

Pour afficher une zone de texte, utilisez le composant natif <textarea> du navigateur.

<textarea name="postContent" />

Voir plus d’exemples ci-dessous.

Props

<textarea> prend en charge toutes les props communes aux éléments.

Une zone de texte peut devenir un champ contrôlé en lui passant une prop value :

  • value : une chaîne de caractères. Contrôle le texte dans la zone de texte.

Lorsque vous passez value, vous devez également passer un gestionnaire d’événement onChange qui met à jour la valeur passée.

Si votre <textarea> n’est pas contrôlée, passez plutôt la prop defaultValue :

  • defaultValue : une chaîne de caractères. Spécifie la valeur initiale pour une zone de texte.

Ces props de <textarea> sont compatibles avec les zones de texte contrôlées et non contrôlées :

  • autoComplete : soit 'on' ou 'off'. Spécifie le comportement de l’autocomplétion.
  • autoFocus : un booléen. Si true, React va activer l’élément après le montage (l’apparition initiale dans le DOM, NdT).
  • children : <textarea> n’accepte pas d’enfants. Pour définir sa valeur initiale, utilisez defaultValue.
  • cols : un nombre. Spécifie la largeur par défaut en prenant pour unité la largeur moyenne des caractères. Par défaut, 20.
  • disabled : un booléen. Si true, la zone de texte ne sera pas interactive et sera grisée.
  • form : une chaîne de caractères. Spécifie l’id du <form> auquel appartient cette zone de texte. S’il est absent, la zone de saisie sera associée au formulaire parent le plus proche.
  • maxLength : un nombre. Spécifie la longueur maximale du texte.
  • minLength : un nombre. Spécifie la longueur minimale du texte.
  • name : une chaîne de caractères. Spécifie le nom de cette zone de texte au sein de l’envoi du formulaire.
  • onChange : une fonction gestionnaire d’événement. Requise pour les zones de texte contrôlées. Se déclenche immédiatement lorsque la valeur de la zone de texte est modifiée par l’utilisateur (par exemple, elle se déclenche à chaque frappe). Se comporte comme l’événement input du navigateur.
  • onChangeCapture : une version de onChange qui se déclenche lors de la phase de capture.
  • onInput : une fonction gestionnaire d’événement. Se déclenche immédiatement lorsque la valeur de la zone de texte est modifiée par l’utilisateur. Pour des raisons historiques, en React, il est préférable d’utiliser onChange à la place, qui fonctionne de manière similaire.
  • onInputCapture : une version de onInput qui se déclenche lors de la phase de capture.
  • onInvalid : une fonction gestionnaire d’événement. Se déclenche si une zone de texte échoue à la validation lors de la soumission du formulaire. Contrairement à l’événement natif invalid, l’événement React onInvalid se propage.
  • onInvalidCapture : une version de onInvalid qui se déclenche lors de la phase de capture.
  • onSelect : une fonction gestionnaire d’événement. Se déclenche après que la sélection à l’intérieur de la zone de texte a changé. React étend l’événement onSelect pour se déclencher également pour une sélection vide et sur les modifications de texte (qui peuvent affecter la sélection).
  • onSelectCapture : une version de onSelect qui se déclenche lors de la phase de capture.
  • placeholder : une chaîne de caractères. Affichée dans une couleur discrète lorsque la valeur de la zone de texte est vide.
  • readOnly : un booléen. Si true, la zone de texte n’est pas modifiable par l’utilisateur.
  • required : un booléen. Si true, la valeur doit être fournie pour que le formulaire puisse être soumis.
  • rows : un nombre. Spécifie la hauteur par défaut en prenant pour unité la hauteur moyenne des caractères. Par défaut, 2.
  • wrap : peut être 'hard', 'soft', ou 'off'. Spécifie comment les retours à la ligne automatiques sont appliqués lors de la soumission d’un formulaire.

Limitations

  • Passer des enfants de cette manière n’est pas autorisé : <textarea>quelque chose</textarea>. Utilisez defaultValue pour définir le contenu initial.
  • Si une zone de texte reçoit une prop value textuelle, elle sera traitée comme contrôlée.
  • Une zone de texte ne peut pas être à la fois contrôlée et non contrôlée.
  • Une zone de texte ne peut pas basculer entre un statut contrôlé et non contrôlé au cours de son existence.
  • Une zone de texte contrôlée doit avoir un gestionnaire onChange qui met à jour sa valeur.

Utilisation

Afficher une zone de texte

Utilisez <textarea> pour afficher une zone de texte. Vous pouvez spécifier sa taille par défaut avec les attributs rows et cols, mais par défaut, l’utilisateur pourra la redimensionner. Pour désactiver le redimensionnement, vous pouvez spécifier resize: none dans le CSS.

export default function NewPost() {
  return (
    <label>
       Écrivez votre article :
      <textarea name="postContent" rows={4} cols={40} />
    </label>
  );
}


Fournir une légende pour une zone de texte

Vous placerez généralement chaque <textarea> à l’intérieur d’une balise <label>. Ça indique au navigateur que cette légende est associée à cette zone de texte. Lorsque l’utilisateur cliquera sur la légende, le navigateur activera la zone de texte. C’est également essentiel pour l’accessibilité : un lecteur d’écran annoncera la légende lorsque l’utilisateur activera la zone de texte.

Si vous ne pouvez pas imbriquer votre <textarea> dans un <label>, associez-les en passant le même id à <textarea id> et <label htmlFor>. Pour éviter les conflits entre les instances d’un composant, générez un id avec useId.

import { useId } from 'react';

export default function Form() {
  const postTextAreaId = useId();
  return (
    <>
      <label htmlFor={postTextAreaId}>
        Écrivez votre article :
      </label>
      <textarea
        id={postTextAreaId}
        name="postContent"
        rows={4}
        cols={40}
      />
    </>
  );
}


Passer une valeur initiale à une zone de texte

Vous pouvez éventuellement spécifier la valeur initiale d’une zone de texte en passant la prop defaultValue :

export default function EditPost() {
  return (
    <label>
      Modifiez votre article :
      <textarea
        name="postContent"
        defaultValue="J’ai beaucoup aimé faire du vélo hier !"
        rows={4}
        cols={40}
      />
    </label>
  );
}

Piège

Contrairement à HTML, passer du texte initial de cette manière n’est pas pris en charge : <textarea>Contenu</textarea>.


Lire la valeur d’une zone de texte lors de la soumission d’un formulaire

Ajoutez un <form> autour de votre zone de texte avec un <button type="submit"> à l’intérieur. Il appellera votre gestionnaire d’événement <form onSubmit>. Par défaut, le navigateur enverra les données du formulaire à l’URL actuelle et rechargera la page. Vous pouvez remplacer ce comportement en appelant e.preventDefault(). Lisez les données du formulaire avec new FormData(e.target).

export default function EditPost() {
  function handleSubmit(e) {
    // Empêche le navigateur de recharger la page
    e.preventDefault();

    // Lit les données du formulaire
    const form = e.target;
    const formData = new FormData(form);

    // Vous pouvez passer formData directement comme
    // corps de la requête fetch :
    fetch('/some-api', { method: form.method, body: formData });

    // Ou vous pouvez travailler avec comme un
    // objet simple :
    const formJson = Object.fromEntries(formData.entries());
    console.log(formJson);
  }

  return (
    <form method="post" onSubmit={handleSubmit}>
      <label>
        Titre de l’article : <input name="postTitle" defaultValue="Faire du vélo" />
      </label>
      <label>
        Modifiez votre article :
        <textarea
          name="postContent"
          defaultValue="J’ai beaucoup aimé faire du vélo hier !"
          rows={4}
          cols={40}
        />
      </label>
      <hr />
      <button type="reset">Abandonner les modifications</button>
      <button type="submit">Sauvegarder l’article</button>
    </form>
  );
}

Remarque

Donnez un name à votre <textarea>, par exemple <textarea name="postContent" />. Le name que vous avez spécifié sera utilisé comme clé dans les données du formulaire, par exemple { postContent: "Votre article" }.

Piège

Par défaut, n’importe quel <button> à l’intérieur d’un <form> va le soumettre. Cela peut être surprenant ! Si vous avez votre propre composant React Button, envisagez de renvoyer <button type="button"> au lieu de <button>. Ensuite, pour être explicite, utilisez <button type="submit"> pour les boutons qui sont censés soumettre le formulaire.


Contrôler une zone de texte avec une variable d’état

Une zone de texte comme <textarea /> est non contrôlée. Même si vous passez une valeur initiale comme <textarea defaultValue="Texte initial" />, votre JSX ne spécifie que la valeur initiale, il ne contrôle pas la valeur actuelle.

Pour afficher une zone de texte contrôlée, passez une prop value à <textarea />. React forcera la zone de texte à toujours avoir la valeur que vous avez passée. Généralement, vous contrôlerez une zone de texte en déclarant une variable d’état :

function NewPost() {
const [postContent, setPostContent] = useState(''); // Déclare une variable d’état...
// ...
return (
<textarea
value={postContent} // ...force la valeur du champ de saisie à la valeur de la variable d'état...
onChange={e => setPostContent(e.target.value)} // ...et met à jour la variable d'état à chaque frappe !
/>
);
}

C’est utile lorsque vous voulez rafraîchir une partie de l’interface utilisateur à chaque frappe.

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

Piège

Si vous passez value sans onChange, il sera impossible de réaliser une saisie dans la zone de texte. Lorsque vous contrôlez une zone de texte en passant une value, vous forcez la zone de texte à toujours avoir la valeur que vous avez passée. Donc, si vous passez une variable d’état comme value mais oubliez de mettre à jour cette variable d’état de manière synchrone au sein du gestionnaire d’événement onChange, React réinitialisera la zone de texte, après chaque frappe, à la value que vous avez spécifiée.


Dépannage

Ma zone de texte ne se met pas à jour lorsque je tape dedans

Si vous affichez une zone de texte avec value mais sans onChange, vous verrez une erreur dans la console :

// 🔴 Bug : zone de texte contrôlée sans gestionnaire onChange
<textarea value={something} />
Console
You provided a 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.

(« Vous avez fourni une prop value à un champ de formulaire sans gestionnaire onChange. Ça produira un champ en lecture seule. Si le champ doit être modifiable utilisez defaultValue. Sinon, définissez soit onChange soit readOnly. », NdT)

Comme le message d’erreur le suggère, si vous ne voulez spécifier que la valeur initiale de la zone de texte, passez plutôt defaultValue :

// ✅ Correct : zone de texte non contrôlée avec une valeur initiale
<textarea defaultValue={something} />

Si vous voulez contrôler cette zone de texte avec une variable d’état, spécifiez un gestionnaire onChange :

// ✅ Correct : zone de texte contrôlée avec onChange
<textarea value={something} onChange={e => setSomething(e.target.value)} />

Si la valeur est en lecture seule intentionnellement, ajoutez une prop readOnly pour supprimer l’erreur :

// ✅ Correct : zone de texte en lecture seule sans onChange
<textarea value={something} readOnly={true} />

Le curseur de ma zone de texte revient au début à chaque frappe

Si vous contrôlez une zone de texte, vous devez mettre à jour sa variable d’état avec la valeur DOM de la zone de texte pendant le onChange.

Vous ne pouvez pas la mettre à jour avec autre chose que e.target.value :

function handleChange(e) {
// 🔴 Bug : mettre à jour un champ de saisie avec autre chose que e.target.value
setFirstName(e.target.value.toUpperCase());
}

Vous ne pouvez pas la mettre à jour de manière asynchrone :

function handleChange(e) {
// 🔴 Bug : mettre à jour un champ de saisie de manière asynchrone
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}

Pour corriger votre code, mettez à jour de manière synchrone avec e.target.value :

function handleChange(e) {
// ✅ Mettre à jour un champ de saisie contrôlé avec e.target.value de manière synchrone
setFirstName(e.target.value);
}

Si ça ne corrige pas le problème, il est possible que la zone de texte soit supprimée et réinsérée dans le DOM à chaque frappe. Ça peut se produire si vous réinitialisez accidentellement l’état à chaque nouveau rendu. Par exemple, ça peut se produire si la zone de texte ou l’un de ses parents reçoit toujours un attribut key différent, ou si vous imbriquez des définitions de composants (ce qui n’est pas autorisé en React et provoque le remontage du composant « interne » à chaque rendu).


J’ai une erreur : “A component is changing an uncontrolled input to be controlled”

(« Un composant passe un champ non contrôlé en mode contrôlé », NdT)

Si vous passez une value à un composant, cette valeur doit être une chaîne de caractères tout au long de son cycle de vie.

Si vous passez value={undefined} à un composant, puis plus tard value="quelqueChose", React ne saura pas si vous voulez que le composant soit contrôlé ou non. Un composant contrôlé doit toujours recevoir une chaîne de caractères en value, pas null ni undefined.

Si votre value provient d’une API ou d’une variable d’état, elle peut être initialisée à null ou undefined. Dans ce cas, définissez-la avec une chaîne vide ('') initialement, ou passez value={someValue ?? ''} pour vous assurer que value est une chaîne de caractères.