How to Use Next.js Server Actions to Handle Form Submissions
Next.js Server Actions are asynchronous functions that run on the server, but can be invoked from both server-side and client-side components. They are useful for handling form submissions and data mutations in Next.js applications.
In this post, I will show you how to use Next.js Server Actions to create a simple contact form that sends an email to the site owner.
Prerequisites
To follow along, you will need:
- Next.js 13 or later
- A SendGrid account and API key
- A basic understanding of Next.js and React
Setting up the project
First, create a new Next.js project using create-next-app
:
npx create-next-app next-server-actions
Then, install @sendgrid/mail
as a dependency:
npm install @sendgrid/mail
Next, create a .env.local
file in the root of your project and add your SendGrid API key as an environment variable:
SENDGRID_API_KEY=your_sendgrid_api_key
Make sure to add .env.local
to your .gitignore
file to avoid exposing your API key.
Creating the contact form
Now, let’s create a simple contact form component that takes the user’s name, email, and message as inputs. We will use React Hooks to manage the state of the form fields and handle the form submission.
Create a file called ContactForm.js
in the components
folder and add the following code:
export default function ContactForm() {
// Handle form submission
const handleSubmit = async (formData) => {
"user server"
//Here need to write email sending functionality
}
return (
<form action={handleSubmit}>
<div>
<label htmlFor="name">Name</label>
<input
type="text"
id="name"
value={name}
/>
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
value={email}
/>
</div>
<div>
<label htmlFor="message">Message</label>
<textarea
id="message"
value={message}
/>
</div>
<button type="submit">Send</button>
</form>
)
}
As you can see, I am using the user server
decorative keyword for running submission function on server and here we can getformData
by calling their ID. This is how we invoke the server action that we will define next.
Sending Email from the server action function
To create a server action, we need to use the use server
directive at the top of a file or a function. This tells Next.js that the code should run only on the server and not on the client.
From previous function we can continue. First import dependency package
import sgMail from '@sendgrid/mail'
// Set the SendGrid API key
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
And now complete the function for sending email-
// Handle form submission
const handleSubmit = async (formData) => {
"user server"
const rawFormData = {
to: formData.get("email"),
from: "your_sending_email",
subject: `New message from ${formData.get("name")}`,
text: formData.get("message"),
}
//Here need to write email sending functionality
try {
await sgMail.send(rawFormData)
// Send a success response
console.log("Email Send Successfully!")
} catch (error) {
// Send an error response
console.log("Something went wrong, please try again!")
}
}
Here, we are using the use server
directive at the top of the function, which means that all the code from this function are server actions. This function gets the form data from the actions, creates an rawFormData object using the SendGrid mail library, and sends the email using the SendGrid API. It also sends a success or error response accordingly.
Here is the full component code
import sgMail from '@sendgrid/mail'
// Set the SendGrid API key
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
export default function ContactForm() {
// State for the form fields
// State for the form status
const [status, setStatus] = useState('')
// Handle form submission
const handleSubmit = async (formData) => {
"user server"
const rawFormData = {
to: formData.get("email"),
from: "your_sending_email",
subject: `New message from ${formData.get("name")}`,
text: formData.get("message"),
}
//Here need to write email sending functionality
try {
await sgMail.send(rawFormData)
// Send a success response
console.log("Email Send Successfully!")
} catch (error) {
// Send an error response
console.log("Something went wrong, please try again!")
}
}
return (
<form action={handleSubmit}>
<div>
<label htmlFor="name">Name</label>
<input
type="text"
id="name"
value={name}
/>
</div>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
value={email}
/>
</div>
<div>
<label htmlFor="message">Message</label>
<textarea
id="message"
value={message}
/>
</div>
<button type="submit">Send</button>
</form>
)
}
Testing the contact form
To test the contact form, we need to import the ContactForm
component in a page and render it. For example, we can create a file called contact.js
in the pages
folder and add the following code:
import ContactForm from '../components/ContactForm'
export default function ContactPage() {
return (
<div>
<h1>Contact Us</h1>
<ContactForm />
</div>
)
}
Now, if we run npm run dev
and go to http://localhost:3000/contact
, we should see the contact form on the page. We can fill in the form fields and click on the send button to submit the form. If everything works, we should see a success message on the page and receive an email in our inbox.
Conclusion
In this post, we learned how to use Next.js Server Actions to handle form submissions and data mutations on the server. We created a simple contact form that sends an email to the site owner using SendGrid.
Next.js Server Actions are a powerful feature that simplifies the development of Next.js applications by eliminating the need to create API endpoints. They also provide type safety, code reuse, and performance benefits.
If you want to learn more about Next.js Server Actions, you can check out the official documentation or some of the tutorials and articles on the topic.