Skip to main content

React Native Handling Text Input: A Complete Guide to the TextInput Component

Almost every mobile app needs to collect something from the user: a username, a password, a search query, a message, or a payment detail. 

In React Native, all of that starts with one core component: TextInput.

This guide to React Native text input walks you through everything you need: the basics of the TextInput component, managing its value with state, handling events, customizing the keyboard, validating input, building forms, and avoiding common mistakes. 

Every section includes code you can copy into your own project.

What Is the TextInput Component in React Native?

TextInput is a built-in React Native component that lets users type text into your app using the device keyboard. It's the mobile equivalent of the HTML <input> and <textarea> elements, and it maps to native text fields on both iOS and Android, so it feels natural on each platform.

You import it directly from react-native:

import { TextInput } from "react-native";

Basic Usage: Your First TextInput

Here is the simplest possible example:

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

export default function App() {
  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Type something..."
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", padding: 20 },
  input: {
    height: 44,
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 8,
    paddingHorizontal: 12,
  },
});

By default, a TextInput has no border, background, or padding. You need to style it yourself, and it's a good idea to set an explicit height so the field is comfortable to tap.



Managing Input Value with State

To read what the user types, store the value in React state and update it with the onChangeText prop. This pattern is called a controlled component.

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

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

  return (
    <View style={{ padding: 20 }}>
      <TextInput
        value={name}
        onChangeText={setName}
        placeholder="Enter your name"
        style={{ borderWidth: 1, padding: 10, borderRadius: 8 }}
      />
      <Text>Hello, {name || "stranger"}!</Text>
    </View>
  );
}

Unlike the web, onChangeText gives you the text string directly, not an event object. That makes simple cases cleaner. If you need more detail about the change, use onChange, which provides a native event.

Essential TextInput Props

The TextInput component has many props. These are the ones you will use most often:

Prop

What it does

value

The current text shown in the field (for controlled inputs)

onChangeText

Called with the new text every time it changes

placeholder

Hint text shown when the field is empty

placeholderTextColor

Color of the placeholder text

secureTextEntry

Hides the text, ideal for passwords

keyboardType

Chooses which keyboard layout appears

autoCapitalize

Controls automatic capitalization

autoCorrect

Turns spell correction on or off

maxLength

Limits the number of characters

multiline

Allows multiple lines of text

editable

Enables or disables typing

returnKeyType

Changes the label of the keyboard's return key

Choosing the Right Keyboard Type

One of the easiest ways to improve user experience is to show the right keyboard. Use the keyboardType prop to match the data you want.

<TextInput keyboardType="email-address" autoCapitalize="none" placeholder="Email" />
<TextInput keyboardType="numeric" placeholder="Age" />
<TextInput keyboardType="phone-pad" placeholder="Phone number" />
<TextInput keyboardType="url" autoCapitalize="none" placeholder="Website" />

Common values include default, numeric, email-address, phone-pad, number-pad, decimal-pad, and url. A few options are platform-specific, so test on both iOS and Android.

Handling Passwords and Sensitive Input

For passwords, set secureTextEntry to hide characters. You can also pair it with a toggle so users can reveal what they typed.



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

export default function PasswordField() {
  const [password, setPassword] = useState("");
  const [hidden, setHidden] = useState(true);

  return (
    <View>
      <TextInput
        value={password}
        onChangeText={setPassword}
        secureTextEntry={hidden}
        autoCapitalize="none"
        autoCorrect={false}
        placeholder="Password"
        style={{ borderWidth: 1, padding: 10, borderRadius: 8 }}
      />
      <Button
        title={hidden ? "Show" : "Hide"}
        onPress={() => setHidden(!hidden)}
      />
    </View>
  );
}

Also consider the textContentType (iOS) and autoComplete (Android) props so password managers and autofill work properly.

Handling Input Events

Besides onChangeText, TextInput offers several events that let you respond to what the user is doing:

  • onFocus: Fires when the field is tapped and gains focus.
  • onBlur: Fires when the field loses focus. This is a great time to validate.
  • onSubmitEditing: Fires when the user presses the keyboard's submit or return key.
  • onEndEditing: Fires when the user finishes editing.
  • onKeyPress: Fires on each key press, useful for special key handling.
<TextInput
  value={query}
  onChangeText={setQuery}
  onFocus={() => console.log("Focused")}
  onBlur={() => console.log("Blurred")}
  onSubmitEditing={() => search(query)}
  returnKeyType="search"
/>

Multiline Text Input

For comments, bios, or messages, enable multiline and control the height with numberOfLines or styling.

<TextInput
  multiline
  numberOfLines={4}
  value={bio}
  onChangeText={setBio}
  placeholder="Tell us about yourself"
  textAlignVertical="top"
  style={{ height: 100, borderWidth: 1, padding: 10, borderRadius: 8 }}
/>

On Android, multiline fields center their text vertically by default, so add textAlignVertical="top" for the expected behavior.

Moving Focus Between Inputs with Refs

In a form, users expect the next field to be focused when they press the return key. You can do that with useRef.

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

export default function LoginForm() {
  const passwordRef = useRef(null);
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <View>
      <TextInput
        value={email}
        onChangeText={setEmail}
        placeholder="Email"
        keyboardType="email-address"
        autoCapitalize="none"
        returnKeyType="next"
        onSubmitEditing={() => passwordRef.current?.focus()}
      />
      <TextInput
        ref={passwordRef}
        value={password}
        onChangeText={setPassword}
        placeholder="Password"
        secureTextEntry
        returnKeyType="done"
      />
    </View>
  );
}

The ref also gives you methods like focus(), blur(), and clear(), which are handy for programmatic control.

Validating Text Input

Good validation tells users what went wrong without annoying them. A common approach is to validate on blur or on submit and store any error message in state.



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

export default function EmailField() {
  const [email, setEmail] = useState("");
  const [error, setError] = useState("");

  const validate = () => {
    const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    setError(valid ? "" : "Please enter a valid email address");
  };

  return (
    <View>
      <TextInput
        value={email}
        onChangeText={setEmail}
        onBlur={validate}
        keyboardType="email-address"
        autoCapitalize="none"
        placeholder="Email"
        style={{
          borderWidth: 1,
          borderColor: error ? "red" : "#ccc",
          padding: 10,
          borderRadius: 8,
        }}
      />
      {error ? <Text style={{ color: "red" }}>{error}</Text> : null}
    </View>
  );
}

For larger forms, consider a library such as React Hook Form together with a schema validator like Zod or Yup. They reduce boilerplate and keep validation logic organized.

Preventing the Keyboard from Covering Your Inputs

On mobile, the keyboard can hide the field being edited. Two built-in tools help:

  • KeyboardAvoidingView: Adjusts the layout so content moves above the keyboard.
  • ScrollView with keyboardShouldPersistTaps="handled": Lets users tap buttons while the keyboard is open instead of needing two taps.
import { KeyboardAvoidingView, Platform, ScrollView } from "react-native";

<KeyboardAvoidingView
  style={{ flex: 1 }}
  behavior={Platform.OS === "ios" ? "padding" : undefined}
>
  <ScrollView keyboardShouldPersistTaps="handled">
    {/* your inputs here */}
  </ScrollView>
</KeyboardAvoidingView>

To dismiss the keyboard when the user taps outside a field, wrap your screen in a Pressable or TouchableWithoutFeedback and call Keyboard.dismiss().

Building a Complete Form Example

Here is a small sign-up form that brings several concepts together:



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

export default function SignUpForm() {
  const [form, setForm] = useState({ name: "", email: "", password: "" });
  const [submitted, setSubmitted] = useState(false);

  const update = (field) => (value) =>
    setForm((prev) => ({ ...prev, [field]: value }));

  const canSubmit =
    form.name.trim() && form.email.includes("@") && form.password.length >= 8;

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Full name"
        value={form.name}
        onChangeText={update("name")}
      />
      <TextInput
        style={styles.input}
        placeholder="Email"
        keyboardType="email-address"
        autoCapitalize="none"
        value={form.email}
        onChangeText={update("email")}
      />
      <TextInput
        style={styles.input}
        placeholder="Password (8+ characters)"
        secureTextEntry
        value={form.password}
        onChangeText={update("password")}
      />
      <Button
        title="Sign up"
        disabled={!canSubmit}
        onPress={() => setSubmitted(true)}
      />
      {submitted && <Text>Thanks for signing up, {form.name}!</Text>}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20, gap: 12 },
  input: { borderWidth: 1, borderColor: "#ccc", borderRadius: 8, padding: 10 },
});

Storing the whole form in one state object keeps your code tidy, and the update helper avoids writing a separate handler for every field.

Best Practices for React Native Text Input

  1. Always use the right keyboard type. It speeds up entry and reduces mistakes.
  2. Set autoCapitalize="none" for emails and usernames.
  3. Provide clear labels, not just placeholders. Placeholders disappear as soon as the user types.
  4. Validate at the right time. Prefer on blur or on submit over every keystroke.
  5. Support autofill and password managers with textContentType and autoComplete.
  6. Make touch targets large enough. Aim for a height of at least 44 points.
  7. Handle the keyboard gracefully with KeyboardAvoidingView and scrollable layouts.
  8. Add accessibility props such as accessibilityLabel so screen readers describe each field.
  9. Avoid heavy work inside onChangeText. Debounce expensive actions like network searches.

Common Mistakes to Avoid

  • Forgetting to pass value along with onChangeText, which creates an uncontrolled input that's hard to reset
  • Using the web-style onChange and expecting e.target.value
  • Leaving autoCorrect on for emails, usernames, and codes
  • Not testing on both iOS and Android, where keyboards and multiline behavior differ
  • Triggering a network request on every keystroke without debouncing
  • Letting the keyboard cover the submit button

Frequently Asked Questions

How do I get the value of a TextInput in React Native?

Store the text in state using useState and update it with the onChangeText prop. The state variable always holds the current value.

How do I clear a TextInput in React Native?

If the input is controlled, set its state back to an empty string. You can also call clear() on a ref attached to the input.

How do I make a TextInput accept only numbers?

Set keyboardType="numeric" to show a number keyboard, then sanitize the value in onChangeText, for example with text.replace(/[^0-9]/g, ""). The keyboard type alone does not guarantee only digits, especially with pasted text.

How do I hide the keyboard programmatically?

Import Keyboard from react-native and call Keyboard.dismiss().

What is the difference between onChange and onChangeText?

onChangeText passes the new text string directly. onChange passes a native event object with more details. Most apps use onChangeText for simplicity.

Should I use a form library in React Native?

For a couple of fields, plain state is fine. For longer forms with complex validation, a library like React Hook Form saves time and reduces bugs.

Popular posts from this blog

How to Set Up a Linux Web Server and Host an HTML Page Easily

Setting up a web server on Linux means spending a fair amount of time in the terminal — Linux leans heavily on the command line rather than clicking through menus, so you'll be typing out instructions more often than not.  If you're new to this, it can feel a little intimidating at first, but the good news is you don't need to become a Linux wizard overnight. A handful of core commands will get you surprisingly far. A few you'll lean on constantly: cd — move between directories ls — see what's in the current directory mkdir — create a new folder nano or vim — edit files right there in the terminal sudo — run something with administrator privileges Get comfortable with these and you'll be able to navigate around, tweak configuration files, and install software without much trouble. You don't need to memorize everything — you just need to be confident enough to follow along with clear instructions, which is exactly what this guide aims to give you....

C++ vcpkg Manifest Mode + CMake

 If you've ever tried to install a C++ library and felt like you were assembling furniture without instructions, this article is for you. We're going to talk about vcpkg manifest mode and how it works with CMake , and I'm going to explain it like you're five years old (in a good way — no judgment here). First, Let's Talk About the Problem In most programming languages, adding a library is easy. Python has pip install requests . JavaScript has npm install express . You type one command, and boom, the library shows up in your project. C++ never really had that. For decades, if you wanted to use a library like fmt or nlohmann/json , you had to: Download the source code yourself Figure out how to compile it Tell your compiler where to find the headers Tell your linker where to find the compiled binaries Cry a little vcpkg is Microsoft's answer to this mess. It's a package manager for C++ — like pip or npm , but for C++ libraries. And manifest mode...

How to Check if Someone is Connected to Your Machine in Linux

Picture this: you glance at your system monitor and notice your CPU is humming along even though you're not running anything demanding. Or maybe your internet feels sluggish for no obvious reason. A small, uneasy thought creeps in — is someone else on my machine right now? For Linux users, this isn't something you have to wonder about. Linux ships with a powerful set of built-in tools that let you see exactly who's connected, who's logged in, and what your network is doing at any given moment. You don't need to be a security expert to use them — you just need to know where to look. This guide walks you through the practical, no-nonsense steps to check for unauthorized connections on your Linux system, with real commands you can run right now. Why Monitoring Network Connections Matters Every device on a network — including your own Linux machine — communicates using an IP address. When another device or user connects to your system, that connection shows up as a trac...