How to Build a Contact Form with SendGrid and Next.js

Contact forms are a crucial component of many websites, allowing visitors to easily get in touch with the site owner or business. Whether you need a way for potential customers to request more info about your product, or simply want to receive feedback and inquiries from your audience, implementing a contact form is often a necessity.

While there are various approaches to building contact forms, using the popular email delivery service SendGrid in combination with the Next.js framework provides a powerful, flexible solution. SendGrid reliably handles the actual sending of email messages, while Next.js makes it simple to create the form UI and handle the backend submission process.

In this guide, we‘ll walk through building a complete contact form solution with SendGrid and Next.js from scratch. By the end, you‘ll have a fully functional form that you can adapt and use in your own projects. Let‘s get started!

Setting Up the Next.js Project

First, we need to create a new Next.js project for our contact form. Make sure you have Node.js and npm installed, then run the following command in your terminal:

npx create-next-app@latest contact-form

This will generate a new directory called contact-form with the base structure of a Next.js app already configured. Navigate into this directory and install a few additional dependencies we‘ll need:

cd contact-form
npm install react-hook-form @sendgrid/mail

Here we‘ve installed the react-hook-form library which will help us manage our form state and validation in React, as well as the official @sendgrid/mail package for interacting with the SendGrid API.

For styling, we‘ll use Tailwind CSS utility classes. Tailwind is already configured by default in new Next.js projects, but if you‘re adding it to an existing project refer to the Tailwind docs for setup instructions.

Creating the Contact Form UI

With our dependencies in place, let‘s start building the actual contact form interface. Create a new file at pages/contact.js and add the following code:

import React from ‘react‘;
import { useForm } from ‘react-hook-form‘;

export default function ContactForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const onSubmit = async (data) => {
    // Handle form submission
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
      <div>
        <label htmlFor="name" className="block mb-1 font-medium">
          Name
        </label>
        <input
          type="text"
          id="name"
          {...register(‘name‘, { required: ‘Name is required‘ })}
          className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
        />
        {errors.name && (
          <p className="mt-1 text-sm text-red-500">{errors.name.message}</p>
        )}
      </div>

      <div>
        <label htmlFor="email" className="block mb-1 font-medium">
          Email
        </label>
        <input
          type="email"
          id="email"
          {...register(‘email‘, { required: ‘Email is required‘ })}
          className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
        />
        {errors.email && (
          <p className="mt-1 text-sm text-red-500">{errors.email.message}</p>
        )}
      </div>

      <div>
        <label htmlFor="message" className="block mb-1 font-medium">
          Message
        </label>
        <textarea
          id="message"
          rows="4"
          {...register(‘message‘, { required: ‘Message is required‘ })}
          className="block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
        ></textarea>
        {errors.message && (
          <p className="mt-1 text-sm text-red-500">{errors.message.message}</p>
        )}
      </div>

      <div>
        <button
          type="submit"
          className="inline-flex items-center rounded-md border border-transparent bg-blue-600 px-4 py-2 font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
        >
          Submit
        </button>
      </div>
    </form>
  );
}

This code sets up a basic form with fields for name, email, and message, as well as a submit button. We‘re using the useForm hook from react-hook-form to manage the form state and handle validation. Each field is registered with the register function, which allows us to specify validation rules and error messages.

The form is styled using Tailwind utility classes. Adjust the colors and spacing as needed to match your site‘s design.

Note that the onSubmit function currently doesn‘t do anything – we‘ll implement the actual form submission logic later once our SendGrid API route is set up.

Configuring SendGrid

In order to send emails from our contact form, we need to set up a SendGrid account and configure a few settings.

First, sign up for a free SendGrid account if you don‘t already have one. Once you‘re logged in, go to Settings > API Keys and click the "Create API Key" button. Give your key a name like "Contact Form" and select the "Restricted Access" option. Under "Mail Send", check the box to grant full access and then click "Create & View".

Copy the generated API key and add it to your Next.js project‘s environment variables. Create a new file called .env.local in the root of your project and add the following line:

SENDGRID_API_KEY=your_api_key_here

Make sure to replace your_api_key_here with the actual key you copied from SendGrid.

Setting Up the SendGrid API Route

Next.js provides a built-in way to create API endpoints directly within your project using a special pages/api directory. This is where we‘ll set up our route to handle sending emails via SendGrid.

Create a new file at pages/api/contact.js and add the following code:

import sendgrid from ‘@sendgrid/mail‘;

sendgrid.setApiKey(process.env.SENDGRID_API_KEY);

export default async function handler(req, res) {
  const { method, body } = req;

  if (method === ‘POST‘) {
    const { name, email, message } = body;

    // Validate form fields
    if (!name || !email || !message) {
      return res.status(400).json({ error: ‘Missing required fields‘ });
    }

    // Send email with SendGrid
    const msg = {
      to: ‘[email protected]‘,
      from: ‘[email protected]‘,
      subject: ‘New Contact Form Submission‘,
      html: `<p><strong>Name:</strong> ${name}</p>
             <p><strong>Email:</strong> ${email}</p>
             <p><strong>Message:</strong></p>
             <pre>${message}</pre>`,
    };

    try {
      await sendgrid.send(msg);
      res.status(200).json({ message: ‘Email sent successfully‘ });
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: ‘Error sending email‘ });
    }
  } else {
    res.status(405).json({ error: ‘Method not allowed‘ });
  }
}

This API route only accepts POST requests. It extracts the name, email, and message fields from the request body and does some basic validation to make sure all required fields are present.

If the fields are valid, it then constructs an email message object with the submitted form data and sends it using the sendgrid.send() method. The "to" address is the email where you want to receive contact form submissions – replace [email protected] with your actual email address. The "from" address should be an email associated with your domain – SendGrid requires this in order to send mail on your behalf.

Finally, the route sends an appropriate HTTP response back to the client indicating whether the email was sent successfully or if there was an error.

Connecting the Form and API

Now that our form component and SendGrid API route are set up, the last step is to connect the two by implementing the form submission logic.

Update the onSubmit function in pages/contact.js with the following code:

const onSubmit = async (data) => {
  try {
    const response = await fetch(‘/api/contact‘, {
      method: ‘POST‘,
      headers: { ‘Content-Type‘: ‘application/json‘ },
      body: JSON.stringify(data),
    });

    if (response.ok) {
      alert(‘Your message was sent successfully!‘);
    } else {
      alert(‘There was an error sending your message. Please try again.‘);
    }
  } catch (error) {
    console.error(error);
    alert(‘There was an error sending your message. Please try again.‘);
  }
};

Here we‘re using the fetch function to send a POST request to our /api/contact route with the form data as JSON in the request body.

If the API responds with a 200 OK status, we show a success message to the user. Otherwise, we display a generic error message. You can customize these messages or add additional logic to handle different error cases as needed.

Testing the Form

At this point, our contact form should be fully functional! Start the Next.js development server by running npm run dev, then navigate to http://localhost:3000/contact in your browser.

Fill out the form with some test data and hit the submit button. If everything is working correctly, you should see an alert indicating that the message was sent successfully, and you should receive an email at the address you specified in the API route.

Deploying to Production

To deploy your Next.js contact form, you can use a hosting service like Vercel which provides built-in support for Next.js projects.

First, push your code to a Git repository on a site like GitHub. Then log in to your Vercel account, click "New Project", and import your contact form repo.

Vercel will automatically detect that it‘s a Next.js project and configure the build settings for you. However, you still need to add your SendGrid API key as an environment variable. In the project settings, go to Environment Variables and add a new variable called SENDGRID_API_KEY with the value set to your actual API key.

Once the environment variable is added, deploy your project and Vercel will build and host your contact form. You can now use the generated production URL to access the form and test that it still sends email successfully.

Additional Resources

Congratulations, you now have a working contact form powered by SendGrid and Next.js! Here are some additional resources you can check out to learn more or extend your form‘s functionality:

I hope this guide has been helpful in walking you through the process of building a contact form with SendGrid and Next.js from start to finish. Feel free to reach out if you have any additional questions!

Similar Posts