TextInput
TextInput is the cross-platform input. Controlled by state; supports keyboard types, autocapitalisation, multiline, ref-based focus — and many platform-specific gotchas.
Controlled, validation, refs, keyboard
EXAMPLE
import { useState, useRef } from 'react';
import {
TextInput,
View,
Text,
Pressable,
Platform,
StyleSheet,
Keyboard,
KeyboardAvoidingView,
ScrollView,
} from 'react-native';
// 1) Basic controlled input
function Email() {
const [email, setEmail] = useState('');
return (
<TextInput
value={email}
onChangeText={setEmail}
placeholder="you@example.com"
placeholderTextColor="#999"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
autoComplete="email"
textContentType="emailAddress" // iOS
inputMode="email"
style={styles.input}
/>
);
}
// 2) Password — secureTextEntry + show/hide
function Password() {
const [pw, setPw] = useState('');
const [show, setShow] = useState(false);
return (
<View style={styles.row}>
<TextInput
value={pw}
onChangeText={setPw}
placeholder="Password"
secureTextEntry={!show}
autoCapitalize="none"
autoComplete="password"
textContentType="password"
style={[styles.input, { flex: 1 }]}
/>
<Pressable onPress={() => setShow(s => !s)} style={styles.iconBtn}>
<Text>{show ? '🙈' : '👁'}</Text>
</Pressable>
</View>
);
}
// 3) Multiline (textarea)
<TextInput
multiline
numberOfLines={4}
style={[styles.input, { textAlignVertical: 'top', minHeight: 96 }]}
placeholder="Comments…"
/>
// 4) Numeric input — typed amount
function Amount() {
const [val, setVal] = useState('');
const onChange = (t) => {
// Allow digits + one dot
const clean = t.replace(/[^0-9.]/g, '').replace(/^(\d*\.\d{0,2}).*$/, '$1');
setVal(clean);
};
return (
<TextInput
value={val}
onChangeText={onChange}
keyboardType="decimal-pad"
placeholder="0.00"
style={styles.input}
/>
);
}
// 5) Refs — focus / blur / clear
function Login() {
const emailRef = useRef(null);
const pwRef = useRef(null);
return (
<View>
<TextInput
ref={emailRef}
returnKeyType="next"
onSubmitEditing={() => pwRef.current?.focus()}
placeholder="Email"
style={styles.input}
/>
<TextInput
ref={pwRef}
returnKeyType="go"
onSubmitEditing={() => submit()}
secureTextEntry
placeholder="Password"
style={styles.input}
/>
</View>
);
}
// 6) Validation — inline error display
function Form() {
const [email, setEmail] = useState('');
const [touched, setTouched] = useState(false);
const error = touched && !/\S+@\S+\.\S+/.test(email) ? 'Invalid email' : '';
return (
<View>
<TextInput
value={email}
onChangeText={setEmail}
onBlur={() => setTouched(true)}
style={[styles.input, !!error && styles.inputError]}
/>
{!!error && <Text style={styles.errorText}>{error}</Text>}
</View>
);
}
// 7) KeyboardAvoidingView — push inputs above the keyboard
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{ flex: 1 }}
>
<ScrollView keyboardShouldPersistTaps="handled">
{/* form fields */}
</ScrollView>
</KeyboardAvoidingView>
// 8) Dismiss keyboard on tap-outside
import { TouchableWithoutFeedback } from 'react-native';
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={{ flex: 1 }}>{/* … */}</View>
</TouchableWithoutFeedback>
// 9) Auto-focus on mount
useEffect(() => { emailRef.current?.focus(); }, []);
// 10) Caret + selection
<TextInput
selection={{ start: 5, end: 10 }}
onSelectionChange={(e) => console.log(e.nativeEvent.selection)}
/>
// 11) Useful prop reference
// - value / onChangeText — controlled binding
// - placeholder / placeholderTextColor
// - keyboardType / inputMode — 'default' | 'email-address' | 'numeric' | 'decimal-pad' | 'number-pad' | 'phone-pad' | 'url'
// - autoCapitalize — 'none' | 'sentences' | 'words' | 'characters'
// - autoCorrect / spellCheck — booleans
// - autoComplete — 'email' | 'password' | 'username' | 'tel' | 'name' | etc.
// - textContentType — iOS-specific OS-level suggestions
// - secureTextEntry — password mode
// - multiline / numberOfLines
// - returnKeyType — 'done' | 'next' | 'go' | 'search' | 'send'
// - blurOnSubmit
// - editable — disabled state
// - maxLength
// - selectTextOnFocus
const styles = StyleSheet.create({
row: { flexDirection: 'row', alignItems: 'center', gap: 8 },
input: { borderWidth: 1, borderColor: '#cbd5e1', borderRadius: 8, padding: 12, fontSize: 16, marginBottom: 12 },
inputError:{ borderColor: '#ef4444' },
errorText:{ color: '#ef4444', fontSize: 13, marginTop: -8, marginBottom: 12 },
iconBtn: { padding: 8 },
});
Why it matters
Match the keyboard to the input: keyboardType=\"email-address\" + autoCapitalize=\"none\" + autoComplete=\"email\". Users notice when the wrong keyboard pops up; OS-level autofill notices the missing hints.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import { TextInput } from 'react-native';
const [name, setName] = useState('');
<TextInput
value={name}
onChangeText={setName}
placeholder="Your name"
style={{ borderWidth: 1, padding: 8 }}
/>
Try it Yourself »
Discussion
Loading…