19
How to build a Contact form with Formik in Next JS and TypeScript
In this article, we'll learn how to build a form using Next, TypeScript, and Formik. We'll be building a simple contact form with basic validation before submitting it. Formik is flexible library for building forms in React and React Native.
Let's create the project for this tutorial. Open your terminal and enter the following command.
npx create-next-app@latest --ts nextjs-formik-demo
This will create a next project based on TypeScript. Here, I've named the project
Once the project initialization is done, go to the project directory and run the development server.
nextjs-formik-demo
.Once the project initialization is done, go to the project directory and run the development server.
cd nextjs-formik-demo
npm run dev
Your server will normally be running on http://localhost:3000.

Great, let's now modify the
index.tsx
file and create the form.Before going further, let's install the
bootstrap
UI package. It'll be very useful to quickly create a form. We'll also install formik
and yup
.npm install bootstrap formik yup
Once it's done go to
First of all, let's import the packages we'll be using.
index.tsx
file and let's start modifying it.First of all, let's import the packages we'll be using.
import { useState } from 'react';
import { useFormik } from 'formik';
import * as yup from 'yup';
import 'bootstrap/dist/css/bootstrap.min.css';
...
Next step, let's create values and object we'll be using for the next steps.
...
import type { NextPage } from 'next';
const Home: NextPage = () => {
const [message, setMessage] = useState(''); // This will be used to show a message if the submission is successful
const [submitted, setSubmitted] = useState(false);
const formik = useFormik({
initialValues: {
email: '',
name: '',
message: '',
},
onSubmit: () => {
setMessage('Form submitted');
setSubmitted(true);
},
validationSchema: yup.object({
name: yup.string().trim().required('Name is required'),
email: yup
.string()
.email('Must be a valid email')
.required('Email is required'),
message: yup.string().trim().required('Message is required'),
}),
});
...
What are we doing here?
useFormik
hooks to create a Formik object. It contains the initial values, the onSubmit
method followed by a validation schema validationSchema
built with Yup
.It's basically all we need for a form in just a few lines. Let's move to the UI and start using the
formik
object....
<div className="vh-100 d-flex flex-column justify-content-center align-items-center">
<div hidden={!submitted} className="alert alert-primary" role="alert">
{message}
</div>
<form className="w-50" onSubmit={formik.handleSubmit}>
{/* Adding the inputs */}
</form>
</div>
...
We want to display an alert every time the form is successfully submitted. That's what this piece of code achieves:
<div hidden={!submitted} className="alert alert-primary" role="alert">
{message}
</div>
We can now add the inputs. For each input, we'll be adding the label, the input and the error message for each field.
Let's start with the
Let's start with the
name
field.<form className="w-50" onSubmit={formik.handleSubmit}>
<div className="mb-3">
<label htmlFor="name" className="form-label">
Name
</label>
<input
type="text"
name="name"
className="form-control"
placeholder="John Doe"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.name && (
<div className="text-danger">{formik.errors.name}</div>
)}
</div>
...
</form>
And then the
email
field.<form className="w-50" onSubmit={formik.handleSubmit}>
...
<div className="mb-3">
<label htmlFor="email" className="form-label">
Email
</label>
<input
type="email"
name="email"
className="form-control"
placeholder="john@example.com"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.email && (
<div className="text-danger">{formik.errors.email}</div>
)}
</div>
...
</form>
And next, the
message
field.<form className="w-50" onSubmit={formik.handleSubmit}>
...
<div className="mb-3">
<label htmlFor="message" className="form-label">
Message
</label>
<textarea
name="message"
className="form-control"
placeholder="Your message ..."
value={formik.values.message}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.message && (
<div className="text-danger">{formik.errors.message}</div>
)}
</div>
...
</form>
And finally the submit button.
<form className="w-50" onSubmit={formik.handleSubmit}>
...
<button type="submit" className="btn btn-primary">
Send
</button>
</form>
And here's the final code of the form.
<div className="vh-100 d-flex flex-column justify-content-center align-items-center">
<div hidden={!submitted} className="alert alert-primary" role="alert">
{message}
</div>
<form className="w-50" onSubmit={formik.handleSubmit}>
<div className="mb-3">
<label htmlFor="name" className="form-label">
Name
</label>
<input
type="text"
name="name"
className="form-control"
placeholder="John Doe"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.name && (
<div className="text-danger">{formik.errors.name}</div>
)}
</div>
<div className="mb-3">
<label htmlFor="email" className="form-label">
Email
</label>
<input
type="email"
name="email"
className="form-control"
placeholder="john@example.com"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.email && (
<div className="text-danger">{formik.errors.email}</div>
)}
</div>
<div className="mb-3">
<label htmlFor="message" className="form-label">
Message
</label>
<textarea
name="message"
className="form-control"
placeholder="Your message ..."
value={formik.values.message}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.message && (
<div className="text-danger">{formik.errors.message}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Send
</button>
</form>
</div>
And the form is operational now. If you noticed, we are conditionally showing errors in the forms using
formik.errors
.{formik.errors.name && (
<div className="text-danger">{formik.errors.name}</div>
)}
This will display an error under the
name
field for example.
Here's the final code for
index.tsx
.import { useState } from 'react';
import { useFormik } from 'formik';
import type { NextPage } from 'next';
import * as yup from 'yup';
import 'bootstrap/dist/css/bootstrap.min.css';
const Home: NextPage = () => {
const [message, setMessage] = useState(''); // This will be used to show a message if the submission is successful
const [submitted, setSubmitted] = useState(false);
const formik = useFormik({
initialValues: {
email: '',
name: '',
message: '',
},
onSubmit: () => {
setMessage('Form submitted');
setSubmitted(true);
},
validationSchema: yup.object({
name: yup.string().trim().required('Name is required'),
email: yup
.string()
.email('Must be a valid email')
.required('Email is required'),
message: yup.string().trim().required('Message is required'),
}),
});
return (
<div className="vh-100 d-flex flex-column justify-content-center align-items-center">
<div hidden={!submitted} className="alert alert-primary" role="alert">
{message}
</div>
<form className="w-50" onSubmit={formik.handleSubmit}>
<div className="mb-3">
<label htmlFor="name" className="form-label">
Name
</label>
<input
type="text"
name="name"
className="form-control"
placeholder="John Doe"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.name && (
<div className="text-danger">{formik.errors.name}</div>
)}
</div>
<div className="mb-3">
<label htmlFor="email" className="form-label">
Email
</label>
<input
type="email"
name="email"
className="form-control"
placeholder="john@example.com"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.email && (
<div className="text-danger">{formik.errors.email}</div>
)}
</div>
<div className="mb-3">
<label htmlFor="message" className="form-label">
Message
</label>
<textarea
name="message"
className="form-control"
placeholder="Your message ..."
value={formik.values.message}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
{formik.errors.message && (
<div className="text-danger">{formik.errors.message}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Send
</button>
</form>
</div>
);
};
export default Home;
And voilà. We've just integrated
Here's a GIF showing the demo.
Formik
to a Next project in Typescript with Boostrap and Yup.Here's a GIF showing the demo.

In this article, we've learned how to build a contact form using Formik and Yup with Next and TypeScript.

19