Custom Styling Examples
React Native Forminput provides extensive styling options to customize the appearance of your form inputs. This page demonstrates advanced styling techniques to help you create beautiful, branded form experiences.
Theme-Based Styling
This example shows how to create a theme system and apply it consistently to FormInput components. It includes a theme switcher to toggle between different visual styles:
import { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { FormInput } from '@react-native-utils/forminput';
const ThemeBasedStyling = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [activeTheme, setActiveTheme] = useState('light');
// Theme styles
const themes = {
light: {
backgroundColor: '#FFFFFF',
textColor: '#333333',
primaryColor: '#4C6FFF',
borderColor: '#E5E7EB',
shadowColor: 'rgba(0, 0, 0, 0.1)',
},
dark: {
backgroundColor: '#1F2937',
textColor: '#F9FAFB',
primaryColor: '#6D8BFF',
borderColor: '#374151',
shadowColor: 'rgba(0, 0, 0, 0.3)',
},
colorful: {
backgroundColor: '#FFF',
textColor: '#333333',
primaryColor: '#FF4C94',
borderColor: '#FFCFE0',
shadowColor: 'rgba(255, 76, 148, 0.2)',
}
};
const theme = themes[activeTheme];
// Apply theme to FormInput
const formInputStyle = {
backgroundColor: theme.backgroundColor,
inputContainerStyle: {
borderColor: theme.borderColor,
backgroundColor: theme.backgroundColor,
borderRadius: 10,
borderWidth: 1,
shadowColor: theme.shadowColor,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 3,
},
labelStyle: {
color: theme.primaryColor,
fontSize: 14,
fontWeight: '600',
marginBottom: 6,
},
inputStyle: {
color: theme.textColor,
fontWeight: '500',
},
focusedInputContainerStyle: {
borderColor: theme.primaryColor,
borderWidth: 2,
},
};
return (
<View style={[styles.container, { backgroundColor: theme.backgroundColor }]}>
<View style={styles.themeButtons}>
<TouchableOpacity
style={[
styles.themeButton,
{ backgroundColor: themes.light.primaryColor },
activeTheme === 'light' && styles.activeTheme
]}
onPress={() => setActiveTheme('light')}
>
<Text style={styles.themeButtonText}>Light</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.themeButton,
{ backgroundColor: themes.dark.primaryColor },
activeTheme === 'dark' && styles.activeTheme
]}
onPress={() => setActiveTheme('dark')}
>
<Text style={styles.themeButtonText}>Dark</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.themeButton,
{ backgroundColor: themes.colorful.primaryColor },
activeTheme === 'colorful' && styles.activeTheme
]}
onPress={() => setActiveTheme('colorful')}
>
<Text style={styles.themeButtonText}>Colorful</Text>
</TouchableOpacity>
</View>
<FormInput
text={{
labelText: "Your Name",
placeholderText: "Enter your name",
value: name,
}}
style={formInputStyle}
icon={{
leftIcon: "user",
leftIconColor: theme.primaryColor,
}}
core={{
onTextChange: setName,
}}
/>
<View style={styles.spacing} />
<FormInput
text={{
labelText: "Email Address",
placeholderText: "Enter your email",
value: email,
}}
style={formInputStyle}
icon={{
leftIcon: "envelope",
leftIconColor: theme.primaryColor,
}}
core={{
onTextChange: setEmail,
keyboardType: "email-address",
autoCapitalize: "none",
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
borderRadius: 8,
marginVertical: 10,
},
spacing: {
height: 16,
},
themeButtons: {
flexDirection: 'row',
marginBottom: 20,
justifyContent: 'center',
},
themeButton: {
paddingVertical: 8,
paddingHorizontal: 16,
borderRadius: 20,
marginHorizontal: 5,
},
themeButtonText: {
color: '#FFFFFF',
fontWeight: 'bold',
},
activeTheme: {
transform: [{ scale: 1.1 }],
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 3,
elevation: 5,
}
});
Custom Component Styling
You can replace the default FormInput components with your own custom components for complete control over the appearance. This example shows custom label and error components:
import { useState } from 'react';
import { View, Text, StyleSheet, Pressable } from 'react-native';
import { FormInput } from '@react-native-utils/forminput';
const CustomComponentStyling = () => {
const [phone, setPhone] = useState('');
// Custom components
const CustomLabel = ({ text, required }) => (
<View style={styles.customLabelContainer}>
<Text style={styles.customLabelText}>{text}</Text>
{required && <Text style={styles.requiredStar}>*</Text>}
<View style={styles.labelUnderline} />
</View>
);
const CustomErrorText = ({ text }) => (
<View style={styles.customErrorContainer}>
<Text style={styles.customErrorIcon}>⚠️</Text>
<Text style={styles.customErrorText}>{text}</Text>
</View>
);
return (
<View style={styles.container}>
<FormInput
text={{
labelText: "Phone Number",
placeholderText: "Enter your phone number",
value: phone,
errorText: "Please enter a valid phone number",
}}
style={{
inputContainerStyle: styles.customInputContainer,
inputStyle: styles.customInput,
focusedInputContainerStyle: styles.customFocusedContainer,
}}
component={{
LabelComponent: ({ text }) => <CustomLabel text={text} required={true} />,
ErrorComponent: ({ text }) => <CustomErrorText text={text} />,
}}
icon={{
leftIcon: "phone",
leftIconColor: "#2563EB",
leftIconSize: 20,
}}
core={{
onTextChange: setPhone,
keyboardType: "phone-pad",
hasError: phone.length > 0 && phone.length < 10,
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
},
customLabelContainer: {
marginBottom: 8,
},
customLabelText: {
fontSize: 16,
color: '#2563EB',
fontWeight: '700',
letterSpacing: 0.5,
},
requiredStar: {
color: '#EF4444',
fontSize: 18,
marginLeft: 4,
position: 'absolute',
right: -10,
top: -2,
},
labelUnderline: {
height: 2,
width: 30,
backgroundColor: '#2563EB',
marginTop: 4,
borderRadius: 2,
},
customInputContainer: {
borderWidth: 2,
borderColor: '#D1D5DB',
borderRadius: 12,
paddingHorizontal: 16,
backgroundColor: '#F9FAFB',
},
customFocusedContainer: {
borderColor: '#2563EB',
backgroundColor: '#EFF6FF',
shadowColor: '#2563EB',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
elevation: 3,
},
customInput: {
fontSize: 16,
color: '#1F2937',
fontWeight: '500',
},
customErrorContainer: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 6,
backgroundColor: '#FEF2F2',
padding: 8,
borderRadius: 6,
},
customErrorIcon: {
marginRight: 6,
fontSize: 14,
},
customErrorText: {
color: '#DC2626',
fontSize: 12,
fontWeight: '500',
},
});
Animated Input Styling
Create engaging user experiences with animated form inputs. This example demonstrates how to use React Native Animated API with FormInput to create focus/blur animations:
import { useState, useRef } from 'react';
import { View, Text, StyleSheet, Animated, Easing } from 'react-native';
import { FormInput } from '@react-native-utils/forminput';
const AnimatedInputStyling = () => {
const [comment, setComment] = useState('');
const scaleAnim = useRef(new Animated.Value(1)).current;
const colorAnim = useRef(new Animated.Value(0)).current;
const animatedBorderColor = colorAnim.interpolate({
inputRange: [0, 1],
outputRange: ['#D1D5DB', '#6366F1'],
});
const handleFocus = () => {
Animated.parallel([
Animated.spring(scaleAnim, {
toValue: 1.02,
tension: 100,
friction: 5,
useNativeDriver: true,
}),
Animated.timing(colorAnim, {
toValue: 1,
duration: 300,
easing: Easing.ease,
useNativeDriver: false,
})
]).start();
};
const handleBlur = () => {
Animated.parallel([
Animated.spring(scaleAnim, {
toValue: 1,
tension: 100,
friction: 5,
useNativeDriver: true,
}),
Animated.timing(colorAnim, {
toValue: 0,
duration: 300,
easing: Easing.ease,
useNativeDriver: false,
})
]).start();
};
const customInputContainer = ({ isFocused, hasError }) => {
return {
Container: Animated.View,
containerStyle: {
transform: [{ scale: scaleAnim }],
borderWidth: 2,
borderColor: hasError ? '#EF4444' : animatedBorderColor,
borderRadius: 12,
padding: 10,
backgroundColor: '#FFFFFF',
shadowColor: hasError ? '#EF4444' : '#6366F1',
shadowOffset: { width: 0, height: isFocused ? 4 : 2 },
shadowOpacity: isFocused ? 0.3 : 0.1,
shadowRadius: isFocused ? 8 : 4,
elevation: isFocused ? 6 : 3,
}
};
};
return (
<View style={styles.container}>
<Text style={styles.title}>Animated Input</Text>
<FormInput
text={{
labelText: "Leave Your Comment",
placeholderText: "Share your thoughts...",
value: comment,
characterLimit: 200,
showCharacterLimit: true,
}}
style={{
multiline: true,
inputHeight: 100,
inputStyle: styles.inputStyle,
labelStyle: styles.labelStyle,
}}
component={{
InputContainerComponent: customInputContainer,
}}
core={{
onTextChange: setComment,
onFocus: handleFocus,
onBlur: handleBlur,
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
backgroundColor: '#F3F4F6',
borderRadius: 12,
},
title: {
fontSize: 18,
fontWeight: '700',
marginBottom: 12,
color: '#4F46E5',
textAlign: 'center',
},
inputStyle: {
fontSize: 16,
lineHeight: 24,
color: '#374151',
},
labelStyle: {
fontSize: 16,
fontWeight: '600',
color: '#4F46E5',
marginBottom: 8,
},
});
Material Design Inputs
Implement Material Design styled inputs with floating labels and underline effects:
import { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { FormInput } from '@react-native-utils/forminput';
const MaterialDesignStyling = () => {
const [username, setUsername] = useState('');
const [bio, setBio] = useState('');
return (
<View style={styles.container}>
<Text style={styles.title}>Material Design Inputs</Text>
<FormInput
text={{
labelText: "Username",
placeholderText: "",
value: username,
helperText: "Pick a username for your profile",
}}
style={{
inputContainerStyle: styles.materialInputContainer,
labelStyle: styles.materialLabel,
inputStyle: styles.materialInput,
focusedInputContainerStyle: styles.materialFocusedContainer,
helperTextStyle: styles.materialHelperText,
floatingLabel: true,
floatingLabelStyle: styles.materialFloatingLabel,
}}
icon={{
leftIcon: "user",
leftIconColor: "#9333EA",
}}
core={{
onTextChange: setUsername,
}}
/>
<View style={styles.spacing} />
<FormInput
text={{
labelText: "Bio",
placeholderText: "",
value: bio,
helperText: "Tell us about yourself",
characterLimit: 150,
showCharacterLimit: true,
}}
style={{
multiline: true,
inputHeight: 100,
inputContainerStyle: styles.materialInputContainer,
labelStyle: styles.materialLabel,
inputStyle: styles.materialInput,
focusedInputContainerStyle: styles.materialFocusedContainer,
helperTextStyle: styles.materialHelperText,
floatingLabel: true,
floatingLabelStyle: styles.materialFloatingLabel,
characterCounterStyle: styles.materialCharCounter,
}}
icon={{
leftIcon: "edit",
leftIconColor: "#9333EA",
}}
core={{
onTextChange: setBio,
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
},
title: {
fontSize: 20,
fontWeight: '700',
marginBottom: 24,
color: '#9333EA',
textAlign: 'center',
},
spacing: {
height: 24,
},
materialInputContainer: {
borderWidth: 0,
borderBottomWidth: 1,
borderRadius: 0,
borderColor: '#D1D5DB',
paddingHorizontal: 0,
paddingBottom: 8,
paddingTop: 16,
},
materialFocusedContainer: {
borderBottomWidth: 2,
borderColor: '#9333EA',
},
materialLabel: {
fontSize: 16,
color: '#6B7280',
fontWeight: '500',
},
materialFloatingLabel: {
fontSize: 12,
color: '#9333EA',
fontWeight: '500',
},
materialInput: {
fontSize: 16,
color: '#111827',
paddingVertical: 8,
},
materialHelperText: {
fontSize: 12,
color: '#6B7280',
marginTop: 4,
marginLeft: 0,
},
materialCharCounter: {
fontSize: 12,
color: '#6B7280',
},
});
Styling Best Practices
- Consistent themes: Define a theme object with colors, spacing, and typography values, then apply them consistently across all inputs
- Accessibility: Ensure sufficient color contrast between text and background colors, and maintain readable font sizes (at least 16px for input text)
- Visual feedback: Use distinct styles for different input states (default, focused, error, disabled) to provide clear visual feedback to users
- Animations: Use subtle animations for state changes to enhance the user experience, but keep them short (under 300ms) to maintain responsiveness
- Custom components: For complex UI requirements, leverage the component prop group to replace default elements with your own implementations
For more information on available styling options, refer to the Style Propsand Component Props documentation.