TextInput - Saisie de Texte

TextInput est le composant React Native pour la saisie de texte. Il remplace l'élément HTML <input> que vous avez utilisé en R4A10. Le principe est le même (composant contrôlé), mais l'API est adaptée au contexte mobile.

Du web au mobile

jsx
// React web (R4A10)
<input
  type="text"
  value={name}
  onChange={(e) => setName(e.target.value)}  // événement avec e.target.value
  placeholder="Votre nom"
/>

// React Native (R4A11)
<TextInput
  value={name}
  onChangeText={setName}                     // reçoit directement la chaîne
  placeholder="Votre nom"
/>

onChangeText vs onChange

La différence principale : en React web, onChange reçoit un événement et vous devez extraire e.target.value. En React Native, onChangeText reçoit directement la chaîne de texte. C'est plus simple : onChangeText={setText} suffit, sans fonction fléchée.

Utilisation de base

jsx
import { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

function NameInput() {
  const [name, setName] = useState('');

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Votre nom :</Text>
      <TextInput
        style={styles.input}
        value={name}
        onChangeText={setName}
        placeholder="Entrez votre nom"
        placeholderTextColor="#999"
      />
      {name.length > 0 && (
        <Text style={styles.preview}>Bonjour {name} !</Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 16 },
  label: { fontSize: 16, fontWeight: '600', marginBottom: 8 },
  input: {
    backgroundColor: '#fff',
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    fontSize: 16,
  },
  preview: { marginTop: 12, fontSize: 16, color: '#0066cc' },
});

TextInput n'a pas de style par défaut

Contrairement à <input> en HTML qui a une bordure et un padding par défaut, TextInput en React Native n'a aucun style par défaut. Sans styles, le champ de saisie est invisible. Pensez à ajouter au minimum : borderWidth, borderColor, padding et fontSize.

Comparaison HTML input vs TextInput

FonctionnalitéHTML <input>React Native <TextInput>
Événement de saisieonChange={(e) => set(e.target.value)}onChangeText={set}
Type de claviertype="email", type="number"keyboardType="email-address"
Mot de passetype="password"secureTextEntry={true}
Zone multiligne<textarea>multiline={true}
Bouton EntréeonSubmit (formulaire)onSubmitEditing + returnKeyType
Styles par défautBordure et padding par défautAucun style (invisible sans style)
Auto-complétionautocomplete="email"autoComplete="email"

Quelle est la différence entre onChange (React web) et onChangeText (React Native) ?

Types de clavier (keyboardType)

Sur mobile, le clavier peut s'adapter au type de données attendu. La prop keyboardType change l'apparence du clavier virtuel :

jsx
// Clavier texte standard (défaut)
<TextInput keyboardType="default" />

// Clavier email (avec @ et .)
<TextInput keyboardType="email-address" />

// Clavier numérique
<TextInput keyboardType="numeric" />

// Clavier téléphone
<TextInput keyboardType="phone-pad" />

// Clavier numérique avec décimales
<TextInput keyboardType="decimal-pad" />

// Clavier URL (avec / et .com)
<TextInput keyboardType="url" />

Choisir le bon clavier

Utiliser le bon type de clavier améliore l'expérience utilisateur : un champ email affiche un clavier avec @, un champ numérique n'affiche que des chiffres. Sur le web, c'est l'attribut type de <input> qui joue ce rôle. Sur mobile, l'impact est plus visible car le clavier virtuel change complètement d'apparence.

Exemple : formulaire avec différents claviers

jsx
import { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

function ContactInfo() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [phone, setPhone] = useState('');
  const [age, setAge] = useState('');

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Nom</Text>
      <TextInput
        style={styles.input}
        value={name}
        onChangeText={setName}
        placeholder="Jean Dupont"
        autoCapitalize="words"       // Majuscule au début de chaque mot
        autoCorrect={false}          // Pas de correction automatique pour les noms
      />

      <Text style={styles.label}>Email</Text>
      <TextInput
        style={styles.input}
        value={email}
        onChangeText={setEmail}
        placeholder="jean@example.com"
        keyboardType="email-address"
        autoCapitalize="none"        // Pas de majuscule pour les emails
        autoCorrect={false}
      />

      <Text style={styles.label}>Téléphone</Text>
      <TextInput
        style={styles.input}
        value={phone}
        onChangeText={setPhone}
        placeholder="06 12 34 56 78"
        keyboardType="phone-pad"
      />

      <Text style={styles.label}>Âge</Text>
      <TextInput
        style={styles.input}
        value={age}
        onChangeText={setAge}
        placeholder="25"
        keyboardType="numeric"
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 16 },
  label: { fontSize: 14, fontWeight: '600', color: '#333', marginBottom: 4, marginTop: 12 },
  input: {
    backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd',
    borderRadius: 8, padding: 12, fontSize: 16,
  },
});

Saisie sécurisée (mot de passe)

Pour les mots de passe, utilisez secureTextEntry :

jsx
import { useState } from 'react';
import { View, TextInput, Pressable, Text, StyleSheet } from 'react-native';

function PasswordInput() {
  const [password, setPassword] = useState('');
  const [showPassword, setShowPassword] = useState(false);

  return (
    <View style={styles.passwordContainer}>
      <TextInput
        style={styles.passwordInput}
        value={password}
        onChangeText={setPassword}
        placeholder="Mot de passe"
        secureTextEntry={!showPassword}   // Masquer les caractères
        autoCapitalize="none"
        autoCorrect={false}
      />
      <Pressable onPress={() => setShowPassword(!showPassword)}>
        <Text style={styles.toggleText}>
          {showPassword ? 'Masquer' : 'Afficher'}
        </Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  passwordContainer: {
    flexDirection: 'row', alignItems: 'center',
    backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd', borderRadius: 8,
  },
  passwordInput: { flex: 1, padding: 12, fontSize: 16 },
  toggleText: { paddingHorizontal: 12, color: '#0066cc', fontWeight: '600' },
});

Comment afficher un clavier avec uniquement des chiffres dans React Native ?

Contrôle de la capitalisation et de la correction

jsx
// Majuscule à chaque mot (noms, villes)
<TextInput autoCapitalize="words" />

// Majuscule à la première lettre de chaque phrase (défaut)
<TextInput autoCapitalize="sentences" />

// Pas de majuscule automatique (emails, identifiants)
<TextInput autoCapitalize="none" />

// Tout en majuscules
<TextInput autoCapitalize="characters" />

// Désactiver la correction automatique (noms propres, code)
<TextInput autoCorrect={false} />

autoCapitalize pour les emails

N'oubliez pas autoCapitalize="none" pour les champs email et mot de passe. Par défaut, le clavier met une majuscule au début de la saisie, ce qui produit des emails comme "Jean@example.com" au lieu de "jean@example.com". C'est une erreur courante sur mobile.

Zone de texte multiligne

Pour des saisies longues (commentaires, notes, descriptions), utilisez multiline :

jsx
<TextInput
  style={[styles.input, styles.textArea]}
  value={description}
  onChangeText={setDescription}
  placeholder="Décrivez votre problème..."
  multiline={true}
  numberOfLines={4}              // Hauteur initiale (Android)
  textAlignVertical="top"        // Texte en haut (Android)
/>
jsx
// Style pour la zone de texte
const styles = StyleSheet.create({
  input: {
    backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd',
    borderRadius: 8, padding: 12, fontSize: 16,
  },
  textArea: {
    height: 120,
    textAlignVertical: 'top',  // Nécessaire sur Android
  },
});

textarea vs multiline

En HTML, vous utilisez <textarea> pour les saisies multilignes. En React Native, il n'y a qu'un seul composant TextInput avec la prop multiline={true}. Comme pour Text qui remplace p, h1 et span, React Native unifie les variantes en un seul composant configurable.

Gestion du clavier

Fermer le clavier

Le clavier virtuel reste ouvert jusqu'à ce que l'utilisateur le ferme ou que vous le fermiez programmatiquement :

jsx
import { Keyboard, Pressable, View } from 'react-native';

// Composant utilitaire : fermer le clavier au tap en dehors
function DismissKeyboard({ children }) {
  return (
    <Pressable onPress={Keyboard.dismiss} style={{ flex: 1 }}>
      {children}
    </Pressable>
  );
}

// Utilisation
function MyScreen() {
  return (
    <DismissKeyboard>
      <View style={styles.container}>
        <TextInput style={styles.input} placeholder="Tapez ici..." />
        {/* Taper en dehors du champ ferme le clavier */}
      </View>
    </DismissKeyboard>
  );
}

Bouton "Entrée" du clavier

La prop returnKeyType change le texte du bouton Entrée du clavier, et onSubmitEditing est appelé quand l'utilisateur appuie dessus :

jsx
<TextInput
  returnKeyType="search"       // "search", "done", "go", "next", "send"
  onSubmitEditing={() => {
    handleSearch();
    Keyboard.dismiss();
  }}
/>

Passer au champ suivant

Pour naviguer entre les champs d'un formulaire avec le bouton "Suivant" du clavier :

jsx
import { useRef } from 'react';

function LoginForm() {
  const passwordRef = useRef(null);

  return (
    <View>
      <TextInput
        placeholder="Email"
        returnKeyType="next"
        onSubmitEditing={() => passwordRef.current?.focus()}
      />
      <TextInput
        ref={passwordRef}
        placeholder="Mot de passe"
        secureTextEntry
        returnKeyType="done"
        onSubmitEditing={() => handleLogin()}
      />
    </View>
  );
}

Navigation entre champs

Sur le web, l'utilisateur utilise la touche Tab pour passer d'un champ à l'autre. Sur mobile, il n'y a pas de touche Tab. Utilisez returnKeyType="next" et onSubmitEditing avec ref.current.focus() pour guider l'utilisateur d'un champ à l'autre. C'est une bonne pratique qui améliore l'expérience de saisie.

Comment naviguer du champ email au champ mot de passe quand l'utilisateur appuie sur 'Suivant' ?

Pourquoi TextInput est-il invisible sans styles ?

À retenir

Comprendre, pas mémoriser

TextInput en résumé :

  • Remplace <input> et <textarea> du HTML
  • onChangeText reçoit directement la chaîne (pas d'événement)
  • keyboardType adapte le clavier au type de données (email, numérique, téléphone)
  • secureTextEntry masque les caractères (mots de passe)
  • autoCapitalize="none" pour les emails et identifiants
  • multiline={true} pour les zones de texte longues
  • returnKeyType et onSubmitEditing pour le bouton Entrée
  • Aucun style par défaut : toujours ajouter bordure, padding, fontSize

Pattern de composant contrôlé (identique au web) :

jsx
const [value, setValue] = useState('');
<TextInput value={value} onChangeText={setValue} />