EthicsComputerCourses
Join training +91 90532 10052

TextInput

React Native · Lesson 6 of 30 Beginner 6 min read Updated

By the end of this lesson you will be able to collect text from users with TextInput, show the right keyboard for each field, hide passwords, and move focus from one field to the next. These are the skills behind every login, search and checkout screen.

Your first TextInput

TextInput is React Native's text box. Like an <input> in web React, you usually make it controlled: the value lives in state, and every change updates that state.

There is one small difference. On the web you read event.target.value inside onChange. React Native gives you a simpler prop, onChangeText, which receives the new text directly.

Step 1: a name field that greets the user as they type.

React JSX
import { useState } from "react";
import { View, Text, TextInput, StyleSheet } from "react-native";

export default function Greeting() {
  const [name, setName] = useState("");

  return (
    <View style={styles.screen}>
      <TextInput
        style={styles.input}
        value={name}
        onChangeText={setName}
        placeholder="Your name"
        placeholderTextColor="#888"
      />
      <Text style={styles.hello}>Namaste, {name || "friend"}!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  screen: { padding: 24, gap: 12 },
  input: { borderWidth: 1, borderColor: "#bbb", borderRadius: 8, padding: 12, fontSize: 16 },
  hello: { fontSize: 18 },
});

What you should see: a bordered box with grey placeholder text. Tap it and the keyboard slides up. As you type "Ananya", the line below changes to "Namaste, Ananya!" letter by letter.

Choosing the right keyboard

A phone can show many keyboards: letters, numbers only, a phone dial pad, or one with an @ key. Showing the right one saves the user time. It is like a ticket counter that hands you a form with only the boxes you need.

FieldProp to useKeyboard shown
Mobile numberinputMode="tel"Phone dial pad
Amount in rupeesinputMode="decimal"Numbers with a decimal point
PIN codeinputMode="numeric"Numbers only
EmailinputMode="email"Letters with @ and .
SearchinputMode="search"Letters with a search key

inputMode is the newer, web-like prop. Older code uses keyboardType, with values such as "phone-pad", "number-pad" and "email-address". Both work; if you set both, inputMode wins.

Passwords, autofill and capitals

Step 2: build a login form with sensible settings for each field.

React JSX
import { useState } from "react";
import { View, TextInput } from "react-native";

export default function LoginFields() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <View style={{ padding: 24, gap: 12 }}>
      <TextInput
        value={email}
        onChangeText={setEmail}
        placeholder="Email"
        inputMode="email"
        autoCapitalize="none"
        autoCorrect={false}
        autoComplete="email"
        style={{ borderWidth: 1, padding: 12, borderRadius: 8 }}
      />
      <TextInput
        value={password}
        onChangeText={setPassword}
        placeholder="Password"
        secureTextEntry
        autoComplete="password"
        style={{ borderWidth: 1, padding: 12, borderRadius: 8 }}
      />
    </View>
  );
}

What you should see: the email field shows an email keyboard and does not capitalise the first letter. The password field shows dots instead of letters. The phone may also offer saved emails and passwords above the keyboard.

  • autoCapitalize="none" stops "Priya@gmail.com" when the user meant "priya@gmail.com". Other values are "sentences" (the default), "words" and "characters".
  • autoCorrect={false} stops the phone "fixing" email addresses into real words.
  • autoComplete tells the system what the field is for, so it can offer autofill. For an SMS code field, autoComplete="one-time-code" helps the phone suggest the code.

Moving from one field to the next

On a long form, users want the keyboard's "Next" key to jump to the next box. You do this with a ref, a way to reach a component directly (see Refs & the DOM in the React course).

Step 3: link two fields together.

React JSX
import { useRef, useState } from "react";
import { View, TextInput } from "react-native";

export default function Address() {
  const cityRef = useRef(null);
  const [street, setStreet] = useState("");
  const [city, setCity] = useState("");

  return (
    <View style={{ padding: 24, gap: 12 }}>
      <TextInput
        value={street}
        onChangeText={setStreet}
        placeholder="House and street"
        returnKeyType="next"
        onSubmitEditing={() => cityRef.current?.focus()}
        style={{ borderWidth: 1, padding: 12 }}
      />
      <TextInput
        ref={cityRef}
        value={city}
        onChangeText={setCity}
        placeholder="City"
        returnKeyType="done"
        style={{ borderWidth: 1, padding: 12 }}
      />
    </View>
  );
}

What you should see: the first keyboard shows a "Next" key. Pressing it moves the cursor into the City field, whose keyboard shows "Done".

For longer notes, add multiline. The box then grows or scrolls, and the return key adds a new line. Use maxLength={200} to limit the number of characters.

Practise the logic: a clean mobile number

Users paste numbers with spaces, dashes or "+91". A good input cleans the text as it arrives. The cleaning and checking is plain JavaScript inside a state update, so try it in the browser. In your app, onChange={(e) => handle(e.target.value)} becomes onChangeText={handle}.

React JSXTry it yourself
import { useState } from "react";
import { createRoot } from "react-dom/client";

function cleanMobile(text) {
  let digits = text.replace(/\D/g, "");
  if (digits.length > 10 && digits.startsWith("91")) {
    digits = digits.slice(2);
  }
  return digits.slice(0, 10);
}

function isValidMobile(digits) {
  return /^[6-9]\d{9}$/.test(digits);
}

function MobileField() {
  const [mobile, setMobile] = useState("");

  function handle(text) {
    setMobile(cleanMobile(text));
  }

  return (
    <div style={{ fontFamily: "sans-serif" }}>
      <input value={mobile} onChange={(e) => handle(e.target.value)} placeholder="Mobile number" />
      <p>{mobile.length === 0 ? "Enter your number" : isValidMobile(mobile) ? "Looks good" : "Enter 10 digits starting with 6-9"}</p>
    </div>
  );
}

console.log(cleanMobile("+91 98765-43210"));
console.log(isValidMobile("9876543210"), isValidMobile("1234567890"));

createRoot(document.getElementById("root")).render(<MobileField />);
Output
9876543210
true false

Paste "+91 98765-43210" into the box. It becomes "9876543210" and the message says "Looks good".

Common mistakes

  • Using onChange and e.target.value. In React Native, use onChangeText, which gives you the string.
  • Invisible inputs on iOS. Add a border or background.
  • Capitalised emails. Set autoCapitalize="none" and autoCorrect={false} on email and username fields.
  • Number fields that return numbers. A TextInput always gives you a string. Convert with Number(text) when you calculate.
  • Forgetting value. Without value, the input is uncontrolled and you cannot clean or reset it from state.

Key points

  • TextInput is the text box; make it controlled with value and onChangeText.
  • inputMode (or the older keyboardType) picks the right keyboard.
  • secureTextEntry hides passwords; autoComplete enables autofill.
  • autoCapitalize and autoCorrect control automatic text changes.
  • Use a ref with onSubmitEditing and focus() to move to the next field.
  • The value is always a string, so convert it before doing maths.

Exercise

Build a "UPI payment" form with two fields: UPI ID and amount. The UPI ID field should not auto-capitalise or auto-correct. The amount field should show a decimal keyboard and accept only digits and one decimal point. The "Next" key on the UPI field should move to the amount. Below the fields, show "Pay ₹AMOUNT to UPI_ID" once both have values.

Show solution
React JSX
import { useRef, useState } from "react";
import { View, Text, TextInput } from "react-native";

export default function PayForm() {
  const amountRef = useRef(null);
  const [upi, setUpi] = useState("");
  const [amount, setAmount] = useState("");

  function onAmount(text) {
    const cleaned = text.replace(/[^0-9.]/g, "");
    const parts = cleaned.split(".");
    setAmount(parts.length > 2 ? parts[0] + "." + parts.slice(1).join("") : cleaned);
  }

  return (
    <View style={{ padding: 24, gap: 12 }}>
      <TextInput value={upi} onChangeText={setUpi} placeholder="name@bank"
        autoCapitalize="none" autoCorrect={false} returnKeyType="next"
        onSubmitEditing={() => amountRef.current?.focus()} style={{ borderWidth: 1, padding: 12 }} />
      <TextInput ref={amountRef} value={amount} onChangeText={onAmount} placeholder="Amount"
        inputMode="decimal" style={{ borderWidth: 1, padding: 12 }} />
      {upi && amount ? <Text>Pay ₹{amount} to {upi}</Text> : null}
    </View>
  );
}

onAmount removes anything that is not a digit or a dot, then joins extra dots away so only one decimal point remains.

Quick Quiz

1. Which prop gives you the new text directly as a string?

2. Which prop hides the characters of a password?

3. What type of value does a TextInput give you when the user types 250?

4. How do you move the cursor to the next field when the user presses "Next"?

Learn React Native with a mentor

Free lessons get you started. Our Mobile App Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call