Skip to main content

Working with Forms and Input

1. Creating Text Inputs

Property Description Default
value Current value of the input field ''
onChangeText Callback function when text is changed () => {}
placeholder Hint text shown when input is empty ''
multiline Allow multiple lines in input false
secureTextEntry Hide input text (e.g., for passwords) false

Example: Basic Text Input

<TextInput
  value={this.state.text}
  onChangeText={(text) => this.setState({ text })}
  placeholder="Enter your name"
  style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
/>

Example: Password Input

<TextInput
  value={this.state.password}
  onChangeText={(text) => this.setState({ password: text })}
  placeholder="Enter password"
  secureTextEntry={true}
  style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
/>

2. Handling Input Changes

Property Description Usage
onChangeText Callback function triggered when text in the input changes onChangeText={(text) => console.log(text)}
onChange Callback function for general input change events (e.g., form submission) onChange={(event) => console.log(event.nativeEvent)}

Example: Handling Text Input Changes

<TextInput
  placeholder="Enter your name"
  onChangeText={(text) => setName(text)}
  value={name}
/>

Example: Managing Multiple Inputs

const [formData, setFormData] = useState({
  username: "",
  email: ""
});

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

<TextInput
  placeholder="Username"
  value={formData.username}
  onChangeText={(text) => handleInputChange("username", text)}
/>
<TextInput
  placeholder="Email"
  value={formData.email}
  onChangeText={(text) => handleInputChange("email", text)}
/>

3. Managing Input Focus

Property Description Usage
focus Controls whether the input is focused focus: true
onFocus Callback when input gains focus onFocus={() => console.log('Focused')}
onBlur Callback when input loses focus onBlur={() => console.log('Blurred')}

Example: Managing Focus with useRef

import React, { useRef } from 'react';
import { TextInput } from 'react-native';

const FocusExample = () => {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current?.focus();
  };

  return (
    <>
      <TextInput
        ref={inputRef}
        placeholder="Press button to focus"
      />
      <Button title="Focus Input" onPress={focusInput} />
    </>
  );
};
Note: In Expo, focus management works similarly to React Native. Use useRef to access the input component and call focus() or blur() methods.

4. Implementing Form Validation

Validation Type Description Implementation Notes
required Ensures field is not empty required HTML5 built-in validation
pattern Matches field against regex pattern="[0-9]{3}-[0-9]{2}-[0-9]{4}" Useful for phone numbers, SSNs
minLength Minimum character count minLength="5" For password strength, etc.
maxLength Maximum character count maxLength="100" Prevents overly long inputs
min / max Numeric range constraints min="18" max="120" For age, score, etc.

Example: Custom Validation with React Hook Form

import { useForm } from "react-hook-form";

function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("email", {
          required: "Email is required",
          pattern: {
            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
            message: "Invalid email address"
          }
        })}
      />
      {errors.email && <p>{errors.email.message}</p>}
      <input type="submit" />
    </form>
  );
}

Example: Server-Side Validation (Node.js)

const express = require("express");
const { body, validationResult } = require("express-validator");

const app = express();

app.post(
  "/submit-form",
  [
    body("username")
      .isLength({ min: 3, max: 20 })
      .withMessage("Username must be between 3 and 20 characters"),
    body("password")
      .isLength({ min: 8 })
      .withMessage("Password must be at least 8 characters")
  ],
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // Proceed with form submission
  }
);
Note: Client-side validation improves UX but should never be the only line of defense. Always validate on the server as well.

5. Using Controlled Inputs

Property Description Example
value Value of the input field, managed by state <TextInput value={text} />
onChangeText Callback function to update state when text changes onChangeText={(t) => setText(t)}

Example: Controlled Input in Expo

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

const ControlledInput = () => {
  const [text, setText] = useState('');

  return (
    <View>
      <TextInput
        value={text}
        onChangeText={setText}
        placeholder="Type here..."
      />
    </View>
  );
};

export default ControlledInput;
Note: Controlled inputs are preferred in React for better form handling and validation.

6. Managing Keyboard Type

Property Values Description
keyboardType default, ascii-capable, numbers-and-punctuation, url, email-address, name-phone-pad, number-pad, phone-pad, twitter, web-search, numeric, decimal-pad Sets the type of keyboard to display for input fields.

Example: Setting Keyboard Type

<TextInput
  placeholder="Enter email"
  keyboardType="email-address"
/>

Example: Numeric Input

<TextInput
  placeholder="Enter age"
  keyboardType="number-pad"
/>

7. Setting Return Key

Property Description Values Notes
returnKeyType Defines the text of the return key "done", "go", "next", "search", "send" Used in TextInput components
onSubmitEditing Callback when return key is pressed Function Triggers when user presses the return key

Example: Setting Return Key Type

<TextInput
  placeholder="Enter text"
  returnKeyType="done"
  onSubmitEditing={() => console.log("Submitted")}
>
</TextInput>

8. Implementing Multi-line Input

Property Description Default
multiline Enables multi-line input in the text area false
numberOfLines Number of lines to display in the input area 3
maxHeight Maximum height of the input area in pixels 200

Example: Multi-line Input Component

{'import React, { useState } from "react";\nimport { TextInput } from "react-native";\n\nconst MultiLineInput = () => {\n  const [text, setText] = useState(""\n\n  return (\n    <TextInput\n      multiline={true}\n      numberOfLines={4}\n      maxHeight={200}\n      value={text}\n      onChangeText={setText}\n      placeholder="Enter multi-line text here..."\n    /\>\n  );\n};\n\nexport default MultiLineInput;'}
Note: The multiline property must be set to true for multi-line input to function correctly.
Warning: Setting maxHeight too low may cause content to be clipped.

9. Using Secure Text Entry

Property Description Default
secureTextEntry Boolean indicating whether to mask input text (e.g., for passwords) false

Example: Secure Text Entry in TextInput

<TextInput
  placeholder="Enter password"
  secureTextEntry={true}
  />
Note: Setting secureTextEntry to true hides the input text with asterisks or dots, enhancing security for sensitive data like passwords.

10. Handling Form Submission

Property Description Example
onSubmit Callback function triggered when the form is submitted handleSubmit = (data) => { console.log(data); }
onSubmitEditing Callback when the user presses Enter in a text input handleEditing = () => { console.log('Editing complete'); }
onSubmitEditing Callback when the user presses Enter in a text input handleEditing = () => { console.log('Editing complete'); }

Example: Basic Form Submission

import React, { useState } from 'react';<br />import { View, TextInput, Button } from 'react-native';<br /><br />const MyForm = () => {<br />  const [formData, setFormData] = useState({<br />    name: '',<br />    email: ''<br />  });<br /><br />  const handleSubmit = (data) => {<br />    console.log('Form submitted:', data);<br />  };<br /><br />  return (<br />    <View><br />      <TextInput<br />        value={formData.name}<br />        onChangeText={(text) => setFormData({...formData, name: text})}<br />        placeholder="Name"<br />      /><br />      <TextInput<br />        value={formData.email}<br />        onChangeText={(text) => setFormData({...formData, email: text})}<br />        placeholder="Email"<br />      /><br />      <Button title="Submit" onPress={() => handleSubmit(formData)} /><br />    </View><br />  );<br />};
Note: In Expo, form handling is typically done using React Native components like TextInput and Button. The onSubmit event is not natively supported on all platforms, so you may need to simulate it using onSubmitEditing or custom logic.
Warning: When using TextInput, ensure that the onChangeText handler updates the state correctly to avoid unexpected behavior during form submission.

11. Creating Custom Input Components

Property Description Example
placeholder Text to display when input is empty placeholder="Enter your name"
value Current value of the input field value={name}
onChange Function to call when input changes onChange={(e) => setName(e.target.value)}
onSubmit Function to call when form is submitted onSubmit={(e) => e.preventDefault()}

Example: Custom Input Component

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

const CustomInput = ({ placeholder, value, onChange }) => {
  return (
    <View style={{ margin: 10 }}>
      <TextInput
        placeholder={placeholder}
        value={value}
        onChangeText={onChange}
        style={{
          borderWidth: 1,
          borderColor: '#ccc',
          padding: 10,
          borderRadius: 5
        }}
      />
    </View>
  );
};

export default CustomInput;

Example: Using Custom Input in a Form

import React, { useState } from 'react';
import { View, Button } from 'react-native';
import CustomInput from './CustomInput';

const FormExample = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = () => {
    console.log({ name, email });
  };

  return (
    <View style={{ padding: 20 }}>
      <CustomInput
        placeholder="Name"
        value={name}
        onChange={setName}
      />
      <CustomInput
        placeholder="Email"
        value={email}
        onChange={setEmail}
      />
      <Button title="Submit" onPress={handleSubmit} />
    </View>
  );
};

export default FormExample;

12. Using Form Libraries

Example: React Hook Form with Expo

// Install: npm install react-hook-form
import { useForm } from "react-hook-form";

export default function MyForm() {
  const { register, handleSubmit } = useForm();
  
  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("name")}
        placeholder="Name"
      />
      <input
        {...register("email")}
        placeholder="Email"
      />
      <button type="submit">Submit</button>
    </form>
  );
}
Library Description Features Notes
React Hook Form Lightweight, performant form library Validation, error handling, controlled inputs Works well with Expo's React Native
Formik Build forms in React and React Native Validation, error handling, field arrays More verbose but very flexible
Final Form Highly flexible form library Validation, async support, field arrays Best for complex forms with many fields
Note: All form libraries require proper integration with Expo's React Native environment and may need additional configuration for native components.

Was this article helpful?