validate-form-in-expo-style

This is a simple React-Native form InputBox with three main feature: 1- Floating Label, 2- Form Validation with custom error message, 3- Left - Right icon in InputBox

Usage no npm install needed!

<script type="module">
  import validateFormInExpoStyle from 'https://cdn.skypack.dev/validate-form-in-expo-style';
</script>

README

React-Native Expo Form Validation Component Library with Floating Label!

N|Solid

😉 Hey! I'm Radhakishan Jangid 😎. More about me Here ↩.

ℹī¸ validate-form-in-expo-style is a Simple form validation component with floating label for React-Native inspired by react-native-form-validator. You can add floating label with this library and can validate form. I created this package for my personal use you can use it in yours too.


My bad, that I don't have Mac or IPhone, so this library is tested only in android. Do check it in Mac and let me know if any problem occurs.


📋 Table of Contents

đŸ“Ĩ Install

$ npm install validate-form-in-expo-style

or

$ yarn add react-native-stylish-accordion

Now we need to install react-native-reanimated and react-lifecycles-compat. If you are using Expo, to ensure that you get the compatible versions of the libraries, run:

expo install react-native-reanimated react-native-gesture-handler react-lifecycles-compat

If you are not using Expo, run the following:

yarn add react-native-reanimated react-native-gesture-handler react-lifecycles-compat

✔ī¸ Supported types:-

  • TextInput

📝 Default Validation Rules are:-

  • matchRegexp
  • isEmail
  • isEmpty
  • required
  • trim
  • isNumber
  • isFloat
  • isPositive
  • minNumber
  • maxNumber
  • minFloat
  • maxFloat
  • minStringLength
  • maxStringLength
  • isString

Some rules that are added in validationName can accept extra parameter for validation, like:

<InputText
   {...otherProps}
   validateNames={['minNumber:1', 'maxNumber:255', 'matchRegexp:^[0-9]

]}
/>

đŸŽĨ See the full example of form validation in react-native Expo:-

Watch the video

💡 How to use:-

import React from 'react';
import { StyleSheet, View, Text, Dimensions, TouchableOpacity, Image, ScrollView } from 'react-native';
import { Form, InputText } from 'validate-form-in-expo-style';
import { FontAwesome, Feather } from "@expo/vector-icons";
class App extends React.Component {
    state = {
        first_name: "",
        number: "",
        last_name: "",
        email: '',
        user: { password: "", repeatPassword: "" },
    }
    componentDidMount() {
        //You can add your own rules
        Form.addValidationRule('isValidPassword', (value) => {
            let passwordReg = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/;
            if (passwordReg.test(value) === false) {
                return false;
            }
            return true;
        });
        Form.addValidationRule('isPasswordMatch', (value) => {
            if (value !== this.state.user.password) {
                return false;
            }
            return true;
        });
    }
    componentWillUnmount() {
       // Remove own rules
        Form.removeValidationRule('isPasswordMatch');
        Form.removeValidationRule('isValidPassword');
    }

    handlePassword = (event) => {
        const { user } = this.state;
        user.password = event.nativeEvent.text;
        this.setState({ user });
    }

    handleRepeatPassword = (event) => {
        const { user } = this.state;
        user.repeatPassword = event.nativeEvent.text;
        this.setState({ user });
    }

    handleChange = (email) => {
        this.setState({ email });
    }

    handleFirstName = (first_name) => {
        this.setState({ first_name });
    }
    handleLastName = (last_name) => {
        this.setState({ last_name });
    }
    handleNumber = (number) => {
        this.setState({ number });
    }
    submit = () => {
        alert("form submit, thank you.")
    }
    handleSubmit = () => {
        this.refs.form.submit();
    }
    render() {
        let Image_Http_URL = { uri: 'https://radhakishan.vpran.in/img/radhakishan-web-3.jpg' };
        const { user } = this.state;
        return (
            <ScrollView>
                <View style={[styles.container, {marginTop: 50}]}>
                    <View style={[styles.action, { alignItems: "center" }]} >
                        <Image source={Image_Http_URL} style={{ width: 100, height: 100, borderRadius: 100 / 2 }} />
                        <FontAwesome name="github" size={24} /><Text style={{fontSize: 18}}>radhakishan404</Text>
                        <Text style={{ fontSize: 20, padding: 10 }}>validate-form-in-expo-style</Text>
                    </View>
                    <View style={styles.action} >
                        <Form ref="form" onSubmit={this.submit} >
                            <InputText
                                name="first_name"
                                label="First Name"
                                placeholder="textfield with floating label"
                                validateNames={['required', "isString", "maxStringLength:30"]}
                                errorMessages={["This field is required", "Only characters allowed", "Max character limit is 30"]}
                                value={this.state.first_name}
                                onChangeText={this.handleFirstName}
                                type="text"
                                leftIcon={<FontAwesome name="user-o" color="#0A3055" size={20} />}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                                validIcon={<Feather name="check-circle" color="green" size={20} />}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <InputText
                                name="last_name"
                                placeholder="textfield without floating label"
                                validateNames={['required', "isString", "maxStringLength:30"]}
                                errorMessages={["This field is required", "Only characters allowed", "Max character limit is 30"]}
                                value={this.state.last_name}
                                onChangeText={this.handleLastName}
                                type="text"
                                leftIcon={<FontAwesome name="user-o" color="#0A3055" size={20} />}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                                validIcon={<Feather name="check-circle" color="green" size={20} />}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <InputText
                                name="phone"
                                label="Mobile"
                                placeholder="textfield with only number"
                                validateNames={['required', "isNumber", "maxStringLength:10"]}
                                errorMessages={["This field is required", "Only numbers allowed", "Max string limit is 10"]}
                                value={this.state.number}
                                onChangeText={this.handleNumber}
                                type="text"
                                leftIcon={<FontAwesome name="phone" color="#0A3055" size={20} />}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                                validIcon={<Feather name="check-circle" color="green" size={20} />}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <InputText
                                name="email"
                                label="email"
                                validateNames={['required', 'validEmail']}
                                errorMessages={['This field is required', 'Enter valid email address']}
                                placeholder="textfield with email validation"
                                type="text"
                                keyboardType="email-address"
                                value={this.state.email}
                                onChangeText={this.handleChange}
                                leftIcon={<FontAwesome name="user-o" color="#0A3055" size={20} />}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                                validIcon={<Feather name="check-circle" color="green" size={20} />}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <InputText
                                name="password"
                                label="Password"
                                secureTextEntry
                                passwordHideIcon={< Ionicons
                                    name="eye-off-outline"
                                    color={constants.white}
                                    size={20}
                                />}
                                passwordShowIcon={< Ionicons
                                    name="eye-outline"
                                    color={constants.white}
                                    size={20}
                                />}
                                validateNames={['isValidPassword', 'required']}
                                errorMessages={['Minimum eight characters, at least one uppercase letter, one lowercase letter and one number', 'This field is required']}
                                type="text"
                                value={user.password}
                                placeholder="custom password validation"
                                leftIcon={<FontAwesome name="lock" color="#0A3055" size={20} />}
                                onChange={this.handlePassword}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <InputText
                                name="repeatPassword"
                                label="Confirm Password"
                                secureTextEntry
                                validateNames={['isPasswordMatch', 'required']}
                                errorMessages={['Password mismatch', 'This field is required']}
                                type="text"
                                value={user.repeatPassword}
                                placeholder="Confirm your password"
                                onChange={this.handleRepeatPassword}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                                leftIcon={<FontAwesome name="lock" color="#0A3055" size={20} />}
                                labelStyle={styles.labelStyle}
                                style={[styles.inputStyle]}
                                containerStyle={styles.inputContainerStyle}
                                floatingTopValue={hp('1%')}
                                floatingFontSize={hp('0.5%')}
                            />
                            <TouchableOpacity
                                activeOpacity={0.8}
                                onPress={this.handleSubmit}
                                style={styles.appButtonContainer}
                            >
                                <Text style={styles.appButtonText}>Submit</Text>
                            </TouchableOpacity>
                        </Form>
                    </View>
                </View>
            </ScrollView>
        );
    }
}

export default App;

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
    action: {
        width: Dimensions.get('window').width,
        padding: 20
    },
    appButtonContainer: {
        elevation: 8,
        backgroundColor: "#009688",
        borderRadius: 10,
        paddingVertical: 10,
        paddingHorizontal: 12,
        marginTop: 10
    },
    appButtonText: {
        fontSize: 18,
        color: "#fff",
        fontWeight: "bold",
        alignSelf: "center",
        textTransform: "uppercase"
    }
    labelStyle: {
        fontSize: hp('1.8%'),
        color: constants.white,
        paddingTop: hp('0.8%'),
        opacity: .9,
        // top: 20
    },
    inputStyle: {
        color: constants.white,
        paddingTop: hp('1%'),
    },
    inputContainerStyle: {
        paddingBottom: hp('1%'),
        paddingTop: hp('1.3%'),
        borderWidth: 2,
        borderBottomWidth: 2,
        // borderColor: "#333333",
        // borderBottomColor: "#333333",
        borderColor: constants.primaryColor,
        borderBottomColor: constants.primaryColor,
        borderRadius: 15
    },
    inputIconStyle: {
        marginHorizontal: 10,
        fontSize: hp('2.3%'),
        backgroundColor: "#333333",
        borderRadius: 5,
        alignSelf: "center",
        paddingHorizontal: hp('0.2%'),
        paddingVertical: hp('0.1%'),
    }
});

🔗 Props

Form Props

Prop Required Type Default value Description
onSubmit true function Callback for form that fires when all validations are passed
instantValidate false bool true If true, form will be validated after each field change. If false, form will be validated only after clicking submit button.
onError false function Callback for form that fires when some of validations are not passed. It will return array of elements which not valid.
debounceTime false number 0 Debounce time for validation i.e. your validation will run after debounceTime ms when you stop changing your input

InputText Props

Prop Required Type Default value Description
name true string Name of input field
label false string Name of input Floating Label
placeholder false string Placeholder of input before any value
validateNames false array Array of validation. See list of default validation rules in above example.
errorMessages false array Array of error messages. Order of messages should be the same as validateNames prop.
errorStyle false object { container: { top: 0, left: 0, position: 'absolute' }, text: { color: 'red' }, underlineValidColor: 'gray', underlineInvalidColor: 'red' } } Add your own error styles
validatorListener false function It triggers after each validation. It will return true or false
withRequiredValidator false bool Allow to use required validator in any validation trigger, not only form submit
leftIcon false code, image Either include image or add Icon tag code to display left icon see above example
invalidIcon false code, image Either include image or add Icon tag code to display error icon on right side see above example
validIcon false code, image Either include image or add Icon tag code to display success icon on right side see above example
secureTextEntry false bool false If true than show hide icon will get added automatically

🔗 Methods

Form Methods

Name Params Return Descriptipon
resetValidations Reset validation messages for all validated inputs
isFormValid dryRun: bool (default true) Promise Get form validation state in a Promise (true if whole form is valid). Run with dryRun = false to show validation errors on form
#### InputText Methods
Name Params Return Descriptipon
getErrorMessage Get error validation message
validate value: any, includeRequired: bool Run validation for current component
isValid bool Return current validation state
makeInvalid Set invalid validation state
makeValid Set valid validation state

đŸ’ŧ Contributing

This component covers all my needs, but feel free to contribute.

🖋 License

MIT Š Radhakishan Jangid