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:

tsx
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:

tsx
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:

tsx
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:

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