Synopsis: We will use NextJS 13 with typescript to create a contact form. Also, to make our job easier, I will use a pre-built form from windstatic.com
Welcome to our tutorial on how to create a contact form with Formspree.io and NextJs. Adding a contact form to your website is essential for engaging with your audience and receiving valuable feedback or inquiries. With Formspree.io, you can easily create customizable forms that are hosted on their platform, and with Next.js, you can seamlessly integrate these forms into your website.
For this tutorial, I will use the NextJs 13 app directory.
In this step-by-step guide, we’ll walk you through the process of setting up your Formspree.io account, creating a form, and integrating it into your Next.js website.
So let’s get started!
Step 1: Create a new Next.js app with Tailwind CSS. If you have questions, follow the official guides from NextJs and TailwindCss.
Note: When I create the next app now with this command "npx create-next-app@latest --experimental-app" Tailwind came with the package.
Step 2: Create a Formspree.io Account To get started, you’ll need to create a free account on Formspree.io. Once you’ve signed up, you’ll be prompted to verify your email address. Follow the verification steps, and you’ll be ready to create your first form.
Step 3: You should see a + button on the left side of the screen. Click on it, create a new project, and provide a name that you like.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1682873398699/f02b1969-3e04-4f37-84c0-ae2fa83241a6.jpeg align="center")
Step 4: Provide the desired name. The name I provided is hashnode. After that, click on "Click + to create a form.".
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1682873510724/10c572d9-5ed0-4ccf-abda-ec79e8c8c878.jpeg align="center")
Step 5: A pop-up will appear that will ask you for the form's name and the email to which you would like the form forwarded. Provide that information and click on "Create Form."
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1682873746598/0b12a0a6-1dab-4d12-aabf-1807bc70ac8e.jpeg align="center")
Step 6: Once you click on Create Form, the form's endpoint should appear. That is all you need.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1682873874732/7ba853d3-86b7-4221-a474-f6c18fd73e4d.jpeg align="center")
Step 7: Go to your code editor, where you have started your next app. Create a components folder under the app folder. Inside the component folder, create a file called "ContactForm.tsx". To make my job easier, I will be using a pre-built form from https://windstatic.com/ which has been created by Mike Abdreuzza. twitter.com/Mike_Andreuzza
Note: Directly copy-pasting the code from Windstatic did not work for me, so I have made some changes to make it work.
Step 8: Inside the ContactForm.tsx file, copy and paste the following code. (Do not forget to add "use client" at the top.) Out here, you will need the formspree endpoint.
"app/components/ContactForm.tsx"
"use client";
import React from "react";
export const ContactForm: React.FC = () => {
return (
<section>
<div className="relative flex justify-center max-h-full overflow-hidden lg:px-0 md:px-12">
<div className="relative z-10 flex flex-col flex-1 px-4 py-10 bg-white shadow-2xl lg:py-24 md:flex-none md:px-28 sm:justify-center">
<div className="w-full max-w-md mx-auto md:max-w-sm md:px-0 md:w-96 sm:px-4">
<div className="flex flex-col">
<div>
<h2 className="text-4xl text-black">Let's get started!</h2>
<p className="mt-2 text-sm text-gray-500">
Complete the details below so I can process your request and
then schedule a time to discuss your goals.
</p>
</div>
</div>
{/* Formspree endpoint goes here with method="POST" */}
<form action="https://formspree.io/f/" method="POST">
<div className="mt-4 space-y-6">
<div>
<label
className="block mb-3 text-sm font-medium text-gray-600"
htmlFor="name"
>
First name
</label>
<input
className="block w-full px-6 py-3 text-black bg-white border border-gray-200 appearance-none rounded-xl placeholder:text-gray-400 focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm"
placeholder="Your name"
name="name"
/>
</div>
<div className="col-span-full">
<label
className="block mb-3 text-sm font-medium text-gray-600"
htmlFor="company"
>
What is the name of your company / organisation?
</label>
<input
className="block w-full px-6 py-3 text-black bg-white border border-gray-200 appearance-none rounded-xl placeholder:text-gray-400 focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm"
placeholder="Company name"
name="company name"
/>
</div>
<div className="col-span-full">
<label
className="block mb-3 text-sm font-medium text-gray-600"
htmlFor="email"
>
How shall we contact you?
</label>
<input
className="block w-full px-6 py-3 text-black bg-white border border-gray-200 appearance-none rounded-xl placeholder:text-gray-400 focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm"
placeholder="email@example.com"
autoComplete="off"
type="email"
name="email"
required
/>
</div>
<div>
<div>
<label
className="block mb-3 text-sm font-medium text-gray-600"
htmlFor="message"
// name="message"
>
Project details
</label>
<div className="mt-1">
<textarea
className="block w-full px-6 py-3 text-black bg-white border border-gray-200 appearance-none rounded-xl placeholder:text-gray-400 focus:border-blue-500 focus:outline-none focus:ring-blue-500 sm:text-sm"
placeholder="What are you working on?"
rows={4}
name="message"
></textarea>
</div>
</div>
</div>
<div className="col-span-full">
<button
className="items-center justify-center w-full px-6 py-2.5 text-center text-white duration-200 bg-black border-2 border-black rounded-full nline-flex hover:bg-transparent hover:border-black hover:text-black focus:outline-none focus-visible:outline-black text-sm focus-visible:ring-black"
type="submit"
>
Submit your request
</button>
</div>
</div>
</form>
</div>
</div>
<div className="hidden bg-white lg:block lg:flex-1 lg:relative sm:contents">
<div className="absolute inset-0 object-cover w-full h-full bg-white">
<img
className="object-center w-full h-auto bg-gray-200"
src="https://d33wubrfki0l68.cloudfront.net/64c901dbc4b16388ef27646a320ad9c1441594df/236fd/images/placeholders/rectangle2.svg"
alt="image"
width="1310"
height="873"
/>
</div>
</div>
</div>
</section>
);
};
Step 9: Go to your main page.tsx file and call for the ContactForm
"app/page.tsx"
import Image from 'next/image'
import { Inter } from 'next/font/google'
import { ContactForm } from './components/conatctForm/ContactForm'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
return (
<ContactForm/>
)
}
Step 10: You are done. Once you fill out the form and click "submit," your form should be sent and visible on the submission tab of Formspree and also in the email account linked.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1682878372663/9ce6819e-b320-4ae4-b9cc-841afdcd0f91.jpeg align="center")
Github Repo Link: https://github.com/trace2798/contact-form_nextjs13_tailwind_typescript
I hope this article helped you.
Happy hacking!