<input>
Le composant natif <input>
du navigateur vous permet d’afficher différents types de champs de saisie dans un formulaire.
<input />
- Référence
- Utilisation
- Afficher des champs de saisie de différents types
- Fournir une légende pour un champ de saisie
- Passer une valeur initiale à un champ de saisie
- Lire la valeur d’un champ de saisie lors de la soumission d’un formulaire
- Contrôler un champ de saisie avec une variable d’état
- Optimiser le recalcul de rendu à chaque frappe clavier
- Dépannage
Référence
<input>
Pour afficher un champ de saisie, utilisez le composant natif <input>
du navigateur.
<input name="myInput" />
Voir plus d’exemples ci-dessous.
Props
<input>
prend en charge toutes les props communes aux éléments.
formAction
: une chaîne de caractères ou une fonction. Cette prop a priorité sur le <form action>
pour les champs de type="submit"
ou type="image"
. Lorsqu’une URL est passée à formAction
, le formulaire se comporte comme un formulaire HTML classique. Mais si une fonction est passée à formAction
, la fonction traitera l’envoi du formulaire. Allez voir <form action>
.
Un champ de saisie peut devenir un champ contrôlé en lui passant une de ces props :
checked
: un booléen. Pour un champ de saisie avec une case à cocher ou un bouton radio, contrôle s’il est sélectionné.value
: une chaîne de caractères. Pour un champ de saisie textuel, contrôle son texte (pour un bouton radio, spécifie la valeur soumise avec le formulaire).
Lorsque vous passez une de ces valeurs, vous devez également passer un gestionnaire d’événement onChange
qui met à jour la valeur passée.
Ces props d’<input>
sont seulement compatibles avec les champs de saisie non contrôlés :
defaultChecked
: un booléen. Spécifie la valeur initiale pour les champs de saisie detype="checkbox"
outype="radio"
.defaultValue
: une chaîne de caractères. Spécifie la valeur initiale pour un champ de saisie textuel.
Ces props d’<input>
sont compatibles avec les champs de saisie contrôlés comme non contrôlés :
accept
: une chaîne de caractères. Spécifie quels types de fichiers sont acceptés par un champ de saisie detype="file"
.alt
: une chaîne de caractères. Spécifie le texte alternatif pour un champ de saisietype="image"
.capture
: une chaîne de caractères. Spécifie le média (microphone, vidéo ou caméra) capturé par un champ de saisietype="file"
.autoComplete
: une chaîne de caractères. Spécifie l’un des comportements d’autocomplétion possibles.autoFocus
: un booléen. Sitrue
, React va activer l’élément après le montage (l’apparition initiale dans le DOM, NdT).dirname
: une chaîne de caractères. Spécifie le nom de la donnée du formulaire indiquant la directionnalité de l’élément.disabled
: un booléen. Sitrue
, le champ de saisie ne sera pas interactif et sera grisé.children
:<input>
n’accepte pas d’enfants.form
: une chaîne de caractères. Spécifie l’id
du<form>
auquel appartient ce champ de saisie. S’il est absent, le champ de saisie sera associé au formulaire parent le plus proche.formAction
: une chaîne de caractères. Remplace l’attributaction
du<form>
parent pour les champs detype="submit"
outype="image"
.formEnctype
: une chaîne de caractères. Remplace l’attributenctype
du<form>
parent pour les champs de saisie detype="submit"
outype="image"
.formMethod
: une chaîne de caractères. Remplace l’attributmethod
du<form>
parent pour les champs de saisie detype="submit"
outype="image"
.formNoValidate
: une chaîne de caractères. Remplace l’attributnovalidate
du<form>
parent pour les champs de saisie detype="submit"
outype="image"
.formTarget
: une chaîne de caractères. Remplace l’attributtarget
du<form>
parent pour les champs de saisie detype="submit"
outype="image"
.height
: une chaîne de caractères. Spécifie la hauteur de l’image pour letype="image"
.list
: une chaîne de caractères. Spécifie l’id
du<datalist>
avec les options d’autocomplétion.max
: un nombre. Spécifie la valeur maximale pour les champs de saisie numériques et de date.maxLength
: un nombre. Spécifie la longueur maximale pour les champs de saisie textuels et autres.min
: un nombre. Spécifie la valeur minimale pour les champs de saisie numériques et de date.minLength
: un nombre. Spécifie la longueur minimale pour les champs de saisie textuels et autres.multiple
: un booléen. Spécifie si plusieurs valeurs sont autorisées pourtype="file"
outype="email"
.name
: une chaîne de caractères. Spécifie le nom de ce champ de saisie au sein de l’envoi du formulaire.onChange
: une fonction gestionnaire d’événement. Requis pour les champs de saisie contrôlés. Se déclenche immédiatement lorsque la valeur du champ de saisie est modifiée par l’utilisateur (par exemple, il se déclenche à chaque frappe). Se comporte comme l’événementinput
du navigateur.onChangeCapture
: une version deonChange
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 du champ de saisie est modifiée par l’utilisateur. Pour des raisons historiques, en React, il est préférable d’utiliseronChange
à la place, qui fonctionne de manière similaire.onInputCapture
: une version deonInput
qui se déclenche lors de la phase de capture.onInvalid
: une fonction gestionnaire d’événement. Se déclenche si un champ de saisie échoue à la validation lors de la soumission du formulaire. Contrairement à l’événement natifinvalid
, l’événement ReactonInvalid
se propage.onInvalidCapture
: une version deonInvalid
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 du champ de saisie a changé. React étend l’événementonSelect
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 deonSelect
qui se déclenche lors de la phase de capture.pattern
: une chaîne de caractères. Spécifie une expression rationnelle qui doit correspondre à lavalue
du champ de saisie.placeholder
: une chaîne de caractères. Affichée dans une couleur discrète lorsque la valeur du champ de saisie est vide.readOnly
: un booléen. Sitrue
, le champ de saisie n’est pas modifiable par l’utilisateur.required
: un booléen. Sitrue
, la valeur doit être fournie pour que le formulaire puisse être soumis.size
: un nombre. Similaire à la définition de la largeur, mais l’unité dépend de la nature du champ.src
: une chaîne de caractères. Spécifie la source de l’image pour un champ de saisietype="image"
.step
: un nombre positif ou le texte'any'
. Spécifie la distance entre les valeurs valides.type
: une chaîne de caractères. L’un des types de saisie.width
: une chaîne de caractères. Spécifie la largeur de l’image pour un champ de saisietype="image"
.
Limitations
- Les cases à cocher ont besoin de
checked
(oudefaultChecked
), pas devalue
(oudefaultValue
). - Si un champ de saisie reçoit une prop
value
textuelle, il sera traité comme un champ contrôlé. - Si un champ de type case à cocher ou bouton radio reçoit une prop
checked
booléenne, il sera traité comme un champ contrôlé. - Un champ de saisie ne peut pas être à la fois contrôlé et non contrôlé.
- Un champ de saisie ne peut pas basculer entre un statut contrôlé et non contrôlé au cours de son existence.
- Un champ de saisie contrôlé doit avoir un gestionnaire
onChange
qui met à jour sa valeur.
Utilisation
Afficher des champs de saisie de différents types
Utilisez un composant <input>
pour afficher un champ de saisie. Par défaut, il s’agira d’un champ de saisie textuel. Vous pouvez passer type="checkbox"
pour une case à cocher, type="radio"
pour un bouton radio, ou l’un des autres types de saisie.
export default function MyForm() { return ( <> <label> Champ de saisie textuel : <input name="myInput" /> </label> <hr /> <label> Case à cocher : <input type="checkbox" name="myCheckbox" /> </label> <hr /> <p> Bouton radio : <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
Fournir une légende pour un champ de saisie
Vous placerez généralement chaque <input>
à l’intérieur d’une balise <label>
. Ça indique au navigateur que cette légende est associée à ce champ de saisie. Lorsque l’utilisateur cliquera sur la légende, le navigateur activera le champ de saisie. C’est également essentiel pour l’accessibilité : un lecteur d’écran annoncera la légende lorsque l’utilisateur activera le champ de saisie.
Si vous ne pouvez pas imbriquer votre <input>
dans un <label>
, associez-les en passant le même id
à <input 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 ageInputId = useId(); return ( <> <label> Votre prénom : <input name="firstName" /> </label> <hr /> <label htmlFor={ageInputId}>Votre âge :</label> <input id={ageInputId} name="age" type="number" /> </> ); }
Passer une valeur initiale à un champ de saisie
Vous pouvez éventuellement spécifier la valeur initiale d’un champ de saisie. Passez-la comme une chaîne de caractères defaultValue
pour les champs de saisie textuels. Les cases à cocher et les boutons radios spécifient quant à eux la valeur initiale avec le booléen defaultChecked
.
export default function MyForm() { return ( <> <label> Champ de saisie textuel : <input name="myInput" defaultValue="Une valeur initiale" /> </label> <hr /> <label> Case à cocher : <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Bouton radio : <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
Lire la valeur d’un champ de saisie lors de la soumission d’un formulaire
Ajoutez un <form>
autour de votre champ de saisie 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 MyForm() { 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> Champ de saisie textuel : <input name="myInput" defaultValue="Une valeur initiale" /> </label> <hr /> <label> Case à cocher : <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Bouton radio : <label><input type="radio" name="myRadio" value="option1" /> Option 1</label> <label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2</label> <label><input type="radio" name="myRadio" value="option3" /> Option 3</label> </p> <hr /> <button type="reset">Abandonner les modifications</button> <button type="submit">Envoyer le formulaire</button> </form> ); }
Contrôler un champ de saisie avec une variable d’état
Un champ de saisie comme <input />
est non contrôlé. Même si vous passez une valeur initiale comme <input defaultValue="Texte initial" />
, votre JSX ne spécifie que la valeur initiale, il ne contrôle pas la valeur actuelle.
Pour afficher un champ de saisie contrôlé, passez une prop value
à <input />
. React forcera le champ de saisie à toujours avoir la valeur que vous avez passée. Généralement, vous contrôlerez un champ de saisie en déclarant une variable d’état :
function Form() {
const [firstName, setFirstName] = useState(''); // Déclare une variable d’état...
// ...
return (
<input
value={firstName} // ...force la valeur du champ de saisie à la valeur de la variable d'état...
onChange={e => setFirstName(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.
function Form() {
const [firstName, setFirstName] = useState('');
return (
<>
<label>
Prénom :
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</label>
{firstName !== '' && <p>Votre prénom est {firstName}.</p>}
...
C’est également utile si vous voulez offrir plusieurs façons d’ajuster l’état de la saisie (par exemple, en cliquant sur un bouton) :
function Form() {
// ...
const [age, setAge] = useState('');
const ageAsNumber = Number(age);
return (
<>
<label>
Âge :
<input
value={age}
onChange={e => setAge(e.target.value)}
type="number"
/>
<button onClick={() => setAge(ageAsNumber + 10)}>
Ajouter 10 ans
</button>
La value
que vous passez aux composants contrôlés ne doit pas être undefined
ou null
. Si vous avez besoin que la valeur initiale soit vide (comme avec le champ firstName
ci-dessous), initialisez votre variable d’état avec une chaîne de caractères vide (''
).
import { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [age, setAge] = useState('20'); const ageAsNumber = Number(age); return ( <> <label> Prénom : <input value={firstName} onChange={e => setFirstName(e.target.value)} /> </label> <label> Âge : <input value={age} onChange={e => setAge(e.target.value)} type="number" /> <button onClick={() => setAge(ageAsNumber + 10)}> Ajouter 10 ans </button> </label> {firstName !== '' && <p>Votre nom est {firstName}.</p> } {ageAsNumber > 0 && <p>Votre âge est {ageAsNumber}.</p> } </> ); }
Optimiser le recalcul de rendu à chaque frappe clavier
Lorsque vous utilisez un champ de saisie contrôlé, vous modifiez l’état à chaque frappe. Si le composant contenant votre état recalcule le rendu d’un grand arbre, ça peut devenir lent. Il existe plusieurs façons d’optimiser les performances d’un recalcul de rendu.
Par exemple, supposons que vous commenciez avec un formulaire qui recalcule tout le contenu de la page à chaque frappe :
function App() {
const [firstName, setFirstName] = useState('');
return (
<>
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
<PageContent />
</>
);
}
Puisque <PageContent />
ne dépend pas de l’état de la saisie, vous pouvez déplacer l’état de la saisie dans son propre composant :
function App() {
return (
<>
<SignupForm />
<PageContent />
</>
);
}
function SignupForm() {
const [firstName, setFirstName] = useState('');
return (
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
);
}
Ça améliore considérablement les performances car maintenant seul SignupForm
se recalcule à chaque frappe.
S’il n’y a aucun moyen d’éviter le recalcul (par exemple, si PageContent
dépend de la valeur de la saisie de recherche), useDeferredValue
vous permet de conserver un champ de saisie contrôlé réactif même au sein d’un recalcul coûteux.
Dépannage
Mon champ de saisie réactif ne se met pas à jour lorsque je tape dedans
Si vous affichez un champ de saisie avec value
mais sans onChange
, vous verrez une erreur dans la console :
// 🔴 Bug : champ de saisie contrôlé sans gestionnaire onChange
<input 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
.(« 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, passez plutôt celle-ci à la prop defaultValue
:
// ✅ Correct : champ de saisie non contrôlé avec une valeur initiale
<input defaultValue={something} />
Si vous voulez contrôler ce champ de saisie avec une variable d’état, spécifiez un gestionnaire onChange
:
// ✅ Correct : champ de saisie contrôlé avec onChange
<input 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 : champ de saisie en lecture seule sans onChange
<input value={something} readOnly={true} />
Ma case à cocher ne se met pas à jour lorsque je clique dessus
Si vous affichez une case à cocher avec checked
mais sans onChange
, vous verrez une erreur dans la console :
// 🔴 Bug : case à cocher contrôlée sans gestionnaire onChange
<input type="checkbox" checked={something} />
checked
prop to a form field without an onChange
handler. This will render a read-only field. If the field should be mutable use defaultChecked
. Otherwise, set either onChange
or readOnly
.Comme le message d’erreur le suggère, si vous ne voulez spécifier que la valeur initiale de la case à cocher, passez plutôt defaultChecked
:
// ✅ Correct : case à cocher non contrôlée avec une valeur initiale
<input type="checkbox" defaultChecked={something} />
Si vous voulez contrôler cette case à cocher avec une variable d’état, spécifiez un gestionnaire onChange
:
// ✅ Correct : case à cocher contrôlée avec onChange
<input type="checkbox" checked={something} onChange={e => setSomething(e.target.checked)} />
Si la case à cocher est en lecture seule intentionnellement, ajoutez une prop readOnly
pour supprimer l’erreur :
// ✅ Correct : champ de saisie en lecture seule sans onChange
<input type="checkbox" checked={something} readOnly={true} />
Le curseur de mon champ de saisie revient au début à chaque frappe
Si vous contrôlez un champ de saisie, vous devez mettre à jour sa variable d’état avec la valeur DOM du champ de saisie pendant le onChange
.
Vous ne pouvez pas le mettre à jour avec autre chose que e.target.value
(ou e.target.checked
pour les cases à cocher) :
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 le 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 le champ de saisie soit supprimé et réinséré 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 le champ de saisie 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.
De la même manière, si vous passez checked
à une case à cocher, assurez-vous que c’est toujours un booléen.