Building a Newsletter Sign-up Form in Next.js
Learn how to build a functional newsletter sign-up form in Next.js using Server Actions and React hooks to manage form state and server-side processing.
Previously in this course, we covered the foundational concepts of Introduction to Server Actions: Handling Forms in Next.js. Now that you understand the basic mechanics of how Next.js processes form submissions on the server, we will apply that knowledge to build a real-world component: a newsletter sign-up form.
In this lesson, we are moving beyond simple data logging. We will build a production-grade form component that handles user input, manages loading states during submission, and integrates seamlessly with our blog’s UI.
Designing the Newsletter Form Markup
A newsletter sign-up form needs to be accessible, performant, and visually integrated into your existing layout. We’ll use semantic HTML to ensure that screen readers and search engines correctly identify the form’s purpose.
Create a new file at components/newsletter-form.tsx. We’ll use a Client Component here because we need to track the form's submission state to provide visual feedback to the user.
TSXCE9178">'use client'; import { useFormStatus } from CE9178">'react-dom'; export default function NewsletterForm() { return ( <form action={/* We'll add our Server Action here */} className="flex flex-col gap-4 p-6 border rounded-lg"> <h2 className="text-xl font-bold">Subscribe to our Newsletter</h2> <input type="email" name="email" placeholder="Enter your email" required className="p-2 border rounded" /> <SubmitButton /> </form> ); } function SubmitButton() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending} className="bg-blue-600 text-white p-2 rounded disabled:bg-gray-400" > {pending ? CE9178">'Subscribing...' : CE9178">'Subscribe'} </button> ); }
Implementing Server-Side Processing

While the form lives in a Client Component for UX purposes, the logic stays on the server. We keep our application secure by keeping sensitive logic out of the browser bundle.
Let’s create an action file at app/actions/newsletter.ts. This is where the actual "work" happens.
TSXCE9178">'use server'; export async function subscribe(formData: FormData) { const email = formData.get(CE9178">'email'); // In a real app, you'd integrate with an API like Mailchimp or a database console.log(CE9178">`Subscribing email: ${email}`); // Simulate network delay await new Promise((resolve) => setTimeout(resolve, 2000)); return { message: CE9178">'Success!' }; }
Now, connect the subscribe action to your form's action attribute.
Handling Form State with React Hooks
The beauty of the App Router is how it bridges the gap between client and server. By using useFormStatus (as shown in the SubmitButton above), we get an automatic way to disable the button and show a "Subscribing..." state without needing to write complex useState logic for every single form in our app.
Practice Exercise
To build your working competence, try the following:
- Import your
subscribeaction into theNewsletterFormcomponent. - Pass the
subscribefunction directly to theactionattribute of your<form>element. - Observe how the
pendingstate updates automatically when the form is submitted.
Common Pitfalls
- Forgetting the 'use server' directive: Every function intended to run on the server must explicitly include
'use server'at the top. - Over-complicating state: Beginners often reach for
useStateto track submission status. UseuseFormStatusinstead; it’s specifically designed for this use case and requires much less boilerplate. - Ignoring Validation: This lesson covers the mechanics of form submission, but never trust client-side validation alone. In the next lesson, we will explore Next.js Server Actions: Zod Form Validation and Progressive Enhancement to ensure the data reaching your server is clean and safe.
FAQ
Q: Can I use this form inside a Server Component?
A: Yes! The form component itself is a Client Component (due to the use client directive), but you can import and render it inside any Server Component in your app.
Q: What if I need to show a success message?
A: You can use useFormState (or the newer useActionState hook) to return a response from the server action and display it in your UI.
Q: Do I need to manage event.preventDefault()?
A: Not with Server Actions. The form handles the submission request automatically when using the action prop.
Recap
In this lesson, we built a functional newsletter sign-up form. We learned to:
- Structure forms using semantic HTML.
- Separate concerns by offloading logic to Server Actions.
- Manage UI states like "submitting" using
useFormStatus.
You now have a solid, server-backed form component ready for your blog.
Up next: Form Validation and Feedback.
Work with me

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.

Next.js Website & Landing Page Development
A blazing-fast, SEO-optimized website or landing page in Next.js — the kind that loads instantly and ranks. Design-to-code, done right.