Newsletter Signup with Benefit List

A newsletter signup section in two columns on a warm cream background. The left column has the newsletter name, a headline, one sentence, an email field with a Subscribe button and a line about how often it is sent. The right column is a numbered list of four things a reader gets in every issue. Submitting the form swaps it for a confirmation message that repeats the address. On phones the form comes first and the list follows.

Code

import { useState } from "react";

const benefits = [
  { title: "One idea you can try by Monday", text: "A single change to a product page, an email or a checkout, with the reasoning behind it." },
  { title: "A real shop, taken apart", text: "We walk through one independent store and show what it does well and what it could drop." },
  { title: "Numbers worth knowing", text: "Shipping rates, ad costs and platform fee changes, summed up in three lines." },
  { title: "Five minutes, no filler", text: "Short enough to read with a coffee. No sponsored posts dressed up as advice." },
];

export default function NewsletterSignupWithBenefitList() {
  const [email, setEmail] = useState("");
  const [done, setDone] = useState(false);

  return (
    <section className="bg-amber-50 px-4 py-16 text-stone-900 sm:px-6 sm:py-20">
      <div className="mx-auto grid max-w-5xl gap-12 lg:grid-cols-2 lg:items-center lg:gap-16">
        <div>
          <p className="text-sm font-semibold uppercase tracking-wider text-orange-800">The Friday Counter</p>
          <h2 className="mt-3 text-3xl font-semibold tracking-tight sm:text-4xl">A weekly letter for people who run small online shops</h2>
          <p className="mt-4 text-lg leading-relaxed text-stone-700">Practical notes on selling more without spending more, written by two people who have packed their own orders.</p>

          {done ? (
            <p role="status" className="mt-8 flex items-start gap-3 rounded-md border border-orange-200 bg-white p-4 text-sm text-stone-800">
              <svg viewBox="0 0 20 20" fill="none" aria-hidden="true" className="mt-0.5 h-5 w-5 flex-none text-orange-700">
                <path d="M4.5 10.5l3.5 3.5 7.5-8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>
                <span className="font-semibold">You are on the list.</span> Check {email} for a link to confirm your address.
              </span>
            </p>
          ) : (
            <form
              className="mt-8 flex flex-col gap-3 sm:flex-row"
              onSubmit={(e) => {
                e.preventDefault();
                if (email.trim()) setDone(true);
              }}
            >
              <label htmlFor="newsletter-email" className="sr-only">Email address</label>
              <input
                id="newsletter-email"
                type="email"
                required
                autoComplete="email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                placeholder="[email protected]"
                className="h-12 w-full rounded-md border border-stone-300 bg-white px-4 text-base text-stone-900 placeholder:text-stone-500 focus:border-orange-700 focus:outline-none focus:ring-2 focus:ring-orange-700/30"
              />
              <button
                type="submit"
                className="h-12 flex-none rounded-md bg-orange-700 px-6 text-sm font-semibold text-white transition hover:bg-orange-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-orange-700 focus-visible:ring-offset-2 focus-visible:ring-offset-amber-50"
              >
                Subscribe
              </button>
            </form>
          )}
          <p className="mt-3 text-sm text-stone-700">Sent every Friday morning. Unsubscribe with one click.</p>
        </div>

        <div>
          <h3 className="text-sm font-semibold uppercase tracking-wider text-stone-700">In every issue</h3>
          <ol className="mt-4 divide-y divide-amber-200 border-y border-amber-200">
            {benefits.map((b, i) => (
              <li key={b.title} className="flex gap-5 py-5">
                <span aria-hidden="true" className="w-7 flex-none text-2xl font-semibold tabular-nums text-orange-700">{i + 1}</span>
                <div>
                  <p className="font-semibold">{b.title}</p>
                  <p className="mt-1 text-sm leading-relaxed text-stone-700">{b.text}</p>
                </div>
              </li>
            ))}
          </ol>
        </div>
      </div>
    </section>
  );
}

Install with one command: npx shadcn@latest add https://we.inc/r/newsletter-signup-with-benefit-list.json

When to use it

How to customize it

Accessibility

Questions

What should a newsletter signup form ask for?

Only the email address. Each extra field lowers the number of people who finish. Ask for a name or interests later, in the welcome email or a preferences page.

Why list benefits next to the form?

An email address has a cost to the person giving it. A short, concrete list of what arrives each week answers "what do I get" at the point of decision, which a bare field cannot do.

How do I connect this to my email provider?

Most providers give you a form endpoint or an API. In `onSubmit`, send the `email` value there with `fetch`, then call `setDone(true)` when the request succeeds and show an error message if it fails.

Should I use double opt-in?

It is a good default. A confirmation link keeps mistyped and fake addresses off your list and is required or expected in several countries. The confirmation message here already tells the reader to check their inbox.

Can I use this without React?

Yes. Copy the HTML version and point the form's `action` at your provider. You lose the inline confirmation, so send people to a thank-you page instead.

Related: Split Hero with Email Capture, Call-to-Action Banner on a Brand Colour, Sticky Bottom Offer Bar, Button Set: Primary, Secondary, Ghost, Icon and Loading.

More forms or all free UI components. Start for free to have a full site built around it.

More in Forms

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap