Form validation is one of the most important tasks when building an app and a form in particular. Itβs one of the most tedious ones as well. Here is a unified approach to handling form validation using a neat library called Formik.
Formik is an open-source library for React and React Native that allows you to easily build forms. It takes care of repetitive and annoying tasks such as handling validation and submission, and keeping track of values, errors, and visited or "touched" fields.
The implementation in this guide is done in React Native. But the approach can easily be translated/ported to a React app.
Let's get started.
Project Setup
Dependency overview
- Expo: Expo is a free and open source toolchain built around React Native to help you build native iOS and Android projects using JavaScript and React. Expo is a great way to get started with React Native.
- UI Kitten: UI Kitten is a React Native framework for creating stunning cross-platform mobile applications. It is based on Eva Design System and provides a set of general purpose UI components styled in a similar way.
- Formik
- Yup: A simple object validation library that works perfectly with Formik.
Initialize Project
We'll start by installing (updating) Expo and initializing a new project
npm i -g expo-cli
npx create-expo-app rn-formik-example
Install the dependecies
Navigate to the application and install these dependencies.
cd rn-formik-example
yarn add @ui-kitten/components @eva-design/eva formik yup
npx expo install react-native-svg@9.13.6
Configure UI Kitten
Wrap the root component App
with ApplicationProvider
from the @ui-kitten/components
library.
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import * as eva from '@eva-design/eva';
import { ApplicationProvider } from '@ui-kitten/components';
export default function App() {
return (
<ApplicationProvider {...eva} theme={eva.light}>
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
</ApplicationProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Design the Form
Using UI Kitten components, let's create a simple registration form component called Register
in src/screens/Register.component.js
import React from 'react';
import { Button, Input, Text } from '@ui-kitten/components';
import { ScrollView, StyleSheet, View } from 'react-native';
export const Register = () => {
return (
<ScrollView>
<View style={styles.container}>
<Input
label="First Name"
placeholder="First Name"
size="large"
style={styles.formCtrl}
/>
<Input
label="Last Name"
placeholder="Last Name"
size="large"
style={styles.formCtrl}
/>
<Input
label="Email Address"
placeholder="name@example.com"
size="large"
style={styles.formCtrl}
/>
<Input
label="Phone Number"
accessoryLeft={() => <Text>+260</Text>}
placeholder="971234567"
size="large"
style={styles.formCtrl}
/>
<Input
label="Password"
placeholder="Password"
size="large"
style={styles.formCtrl}
secureTextEntry
/>
<Input
label="Confirm Password"
placeholder="Confirm Password"
size="large"
style={styles.formCtrl}
secureTextEntry
/>
<Button style={styles.submitBtn}>Register</Button>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
paddingVertical: 50,
paddingHorizontal: 20,
},
formCtrl: {
marginBottom: 30,
},
submitBtn: {
margin: 10,
},
});
Update App.js
to display Register
// Truncated
...
import { Register } from './src/screens/Register.component';
export default function App() {
return (
<ApplicationProvider {...eva} theme={eva.light}>
<Register />
</ApplicationProvider>
);
}
...
// Truncated
You app should look like this.
Create Validation Schema
Using Yup, we'll create a validation schema for the form. Create a new file src/schemas/register.form.js
and add the following code
import * as yup from 'yup';
export const registerSchema = yup.object().shape({
firstName: yup.string().required('First Name is required'),
lastName: yup.string().required('Last Name is required'),
email: yup.string().email('Invalid email').required('Email is required'),
phoneNumber: yup
.string()
.matches(/^[0-9]+$/, 'Must be only digits')
.min(9, 'Must be exactly 9 digits')
.max(9, 'Must be exactly 9 digits')
.required('Phone Number is required'),
password: yup
.string()
.min(8, ({ min }) => `Password must be at least ${min} characters`)
.required('Password is required'),
confirmPassword: yup
.string()
.oneOf([yup.ref('password'), null], 'Passwords must match')
.required('Confirm Password is required'),
});
export const registerInitialValues = {
firstName: '',
lastName: '',
email: '',
phoneNumber: '',
password: '',
confirmPassword: '',
};
Yup's API is pretty easy to understand and use. For example, the firstName
field in the schema is mapped to required string
schema, yup.string().required('First Name is required')
. The form is invalid if no value is given for this field. Yup also allows you to change multiple validation rules for a single field. For example, the phoneNumber
field has multiple validation rules such as, matches
, min
, max
, and required
. Check out the Yup API documentation for more details.
Add Formik to the Form
The simplest way to add Formik to the form is by using the useFormik
hook. Update src/screens/Register.component.js
to use the hook
...
import { useFormik } from 'formik';
import { registerInitialValues, registerSchema } from '../schemas/register.form';
export const Register = () => {
const formik = useFormik({
initialValues: registerInitialValues,
validationSchema: registerSchema,
onSubmit: (values) => {
console.log(values);
Alert.alert(
`Welcome, ${values.firstName}`,
'Your account has been created.'
);
},
});
...
Update the Input
components to handle the formik state for respective fields. For example, the First Name
component should look like this
<Input
label="First Name"
placeholder="First Name"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('firstName')}
onBlur={formik.handleBlur('firstName')}
value={formik.values?.firstName}
/>
Update the Button
component to handle the form submission
<Button style={styles.submitBtn} onPress={formik.handleSubmit}>
Register
</Button>
Add additional props to the Input
components to display validation errors
<Input
label="First Name"
placeholder="First Name"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('firstName')}
onBlur={formik.handleBlur('firstName')}
value={formik.values?.firstName}
status={
formik.touched.firstName && Boolean(formik.errors.firstName)
? 'danger'
: 'basic'
}
caption={formik.touched.firstName && formik.errors.firstName}
/>
Do this for the rest of the Input
components.
The Register
component should look like this
import React from 'react';
import { Button, Input, Text } from '@ui-kitten/components';
import { ScrollView, StyleSheet, View } from 'react-native';
import { useFormik } from 'formik';
import {
registerInitialValues,
registerSchema,
} from '../schemas/register.form';
export const Register = () => {
const formik = useFormik({
initialValues: registerInitialValues,
validationSchema: registerSchema,
onSubmit: (values) => {
console.log(values);
Alert.alert(
`Welcome, ${values.firstName}`,
'Your account has been created.'
);
},
});
return (
<ScrollView>
<View style={styles.container}>
<Input
label="First Name"
placeholder="First Name"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('firstName')}
onBlur={formik.handleBlur('firstName')}
value={formik.values?.firstName}
status={
formik.touched.firstName && Boolean(formik.errors.firstName)
? 'danger'
: 'basic'
}
caption={formik.touched.firstName && formik.errors.firstName}
/>
<Input
label="Last Name"
placeholder="Last Name"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('lastName')}
onBlur={formik.handleBlur('lastName')}
value={formik.values.lastName}
status={
formik.touched.lastName && Boolean(formik.errors.lastName)
? 'danger'
: 'basic'
}
caption={formik.touched.lastName && formik.errors.lastName}
/>
<Input
label="Email Address"
placeholder="name@example.com"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('email')}
onBlur={formik.handleBlur('email')}
value={formik.values.email}
status={
formik.touched.email && Boolean(formik.errors.email)
? 'danger'
: 'basic'
}
caption={formik.touched.email && formik.errors.email}
/>
<Input
label="Phone Number"
accessoryLeft={() => <Text>+260</Text>}
placeholder="971234567"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('phoneNumber')}
onBlur={formik.handleBlur('phoneNumber')}
value={formik.values.phoneNumber}
status={
formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)
? 'danger'
: 'basic'
}
caption={formik.touched.phoneNumber && formik.errors.phoneNumber}
/>
<Input
label="Password"
placeholder="Password"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('password')}
onBlur={formik.handleBlur('password')}
value={formik.values.password}
status={
formik.touched.password && Boolean(formik.errors.password)
? 'danger'
: 'basic'
}
caption={formik.touched.password && formik.errors.password}
secureTextEntry
/>
<Input
label="Confirm Password"
placeholder="Confirm Password"
size="large"
style={styles.formCtrl}
onChangeText={formik.handleChange('confirmPassword')}
onBlur={formik.handleBlur('confirmPassword')}
value={formik.values.confirmPassword}
status={
formik.touched.confirmPassword &&
Boolean(formik.errors.confirmPassword)
? 'danger'
: 'basic'
}
caption={
formik.touched.confirmPassword && formik.errors.confirmPassword
}
secureTextEntry
/>
<Button style={styles.submitBtn} onPress={formik.handleSubmit}>
Register
</Button>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
paddingVertical: 50,
paddingHorizontal: 20,
},
formCtrl: {
marginBottom: 30,
},
submitBtn: {
margin: 10,
},
});
That's it. You have successfully created a form with validation using Formik.
Run your app to test. Depending on your development environment, you can use one of the following commands:
yarn android # for android
yarn ios # for ios
Conclusion
In this tutorial, you have learned how to create a form with validation in React Native using Formik (and UI Kitten). You have also learned how to use the useFormik
hook to handle form state and yup
to define validation rules. You can also use the same approach to create forms in your React web applications.
Source Code
Available on GitHub.
New to React?
I'm offering a 1-on-1, pair programming-styled, remote training in React. Apply here.
Top comments (2)
Amazing post with good examples, Daryl !
3
Thank you, Merdan!