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. |
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.