DEV Community

Radhakishan Jangid
Radhakishan Jangid

Posted on

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

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
Enter fullscreen mode Exit fullscreen mode

or

$ yarn add react-native-stylish-accordion
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If you are not using Expo, run the following:

yarn add react-native-reanimated react-native-gesture-handler react-lifecycles-compat
Enter fullscreen mode Exit fullscreen mode

✔ī¸ 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](https://i.ytimg.com/vi_webp/y7bkVDu0LVA/maxresdefault.webp)](https://youtu.be/y7bkVDu0LVA)

***💡 How to use:-***
----------

`

```javascript
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} />}
                            />
                            <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} />}
                            />
                            <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} />}
                            />
                            <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} />}
                            />
                            <InputText
                                name="password"
                                label="Password"
                                secureTextEntry
                                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}
                                invalidIcon={< Feather
                                    name="alert-circle"
                                    color="red"
                                    size={20}
                                />}
                            />
                            <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} />}
                            />
                            <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"
    }
});
```

`
***🔗 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](https://radhakishan.vpran.in)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)