Docs
Newsletter Signup

Newsletter Signup

A vibrant email capture section with benefits list and modern design. Features bold colors and clean layout for maximum conversions.

Newsletter

Stay in the loop

Get the latest updates, articles, and resources delivered to your inbox weekly.

  • Weekly curated content
  • Exclusive tips and tricks
  • Early access to new features

No spam. Unsubscribe anytime.

Newsletter

Join our community

Subscribe to get insider updates and special offers.

  • Product updates and news
  • Special discounts
  • Community highlights

No spam. Unsubscribe anytime.

Newsletter

Get weekly insights

Join 10,000+ subscribers getting actionable tips every week.

  • Expert insights
  • Case studies
  • Industry trends

No spam. Unsubscribe anytime.

Newsletter

Never miss an update

Be the first to know about new features and updates.

  • Product announcements
  • Feature tutorials
  • Best practices

No spam. Unsubscribe anytime.

Features

  • Vibrant colors - Blue, Purple, Green, Orange variants
  • Split layout - Content and form side-by-side
  • Benefits list - Checkmarks for key value props
  • Email validation - Built-in form validation
  • Decorative elements - Subtle glows and grid pattern
  • Newsletter badge - Mail icon with label
  • Privacy note - "No spam" reassurance
  • Responsive - Stacks beautifully on mobile
  • TypeScript support - Full type safety

Installation

Copy and paste the following code into your project.

"use client";
 
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Check, Loader2, Mail } from "lucide-react";
import { useState } from "react";
 
interface NewsletterSignupProps {
  headline: string;
  description?: string;
  benefits?: string[];
  variant?: "blue" | "purple" | "green" | "orange";
  placeholder?: string;
  buttonText?: string;
  onSubmit?: (email: string) => void;
}
 
const variants = {
  blue: {
    section: "bg-blue-600",
    headline: "text-white",
    description: "text-blue-100",
    benefits: "text-blue-50",
    input:
      "bg-white/10 border-white/20 text-white placeholder:text-white/60 focus:bg-white/20",
    button: "bg-white text-blue-600 hover:bg-blue-50",
    checkmark: "bg-white/20 text-white",
    successBg: "bg-white/10",
  },
  purple: {
    section: "bg-purple-600",
    headline: "text-white",
    description: "text-purple-100",
    benefits: "text-purple-50",
    input:
      "bg-white/10 border-white/20 text-white placeholder:text-white/60 focus:bg-white/20",
    button: "bg-white text-purple-600 hover:bg-purple-50",
    checkmark: "bg-white/20 text-white",
    successBg: "bg-white/10",
  },
  green: {
    section: "bg-green-600",
    headline: "text-white",
    description: "text-green-100",
    benefits: "text-green-50",
    input:
      "bg-white/10 border-white/20 text-white placeholder:text-white/60 focus:bg-white/20",
    button: "bg-white text-green-600 hover:bg-green-50",
    checkmark: "bg-white/20 text-white",
    successBg: "bg-white/10",
  },
  orange: {
    section: "bg-orange-600",
    headline: "text-white",
    description: "text-orange-100",
    benefits: "text-orange-50",
    input:
      "bg-white/10 border-white/20 text-white placeholder:text-white/60 focus:bg-white/20",
    button: "bg-white text-orange-600 hover:bg-orange-50",
    checkmark: "bg-white/20 text-white",
    successBg: "bg-white/10",
  },
};
 
export function NewsletterSignup({
  headline,
  description,
  benefits,
  variant = "blue",
  placeholder = "Enter your email",
  buttonText = "Subscribe",
  onSubmit,
}: NewsletterSignupProps) {
  const [email, setEmail] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isSuccess, setIsSuccess] = useState(false);
  const styles = variants[variant];
  const successMessage = "Check your inbox to confirm your subscription.";
 
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (email && onSubmit) {
      setIsLoading(true);
      try {
        await onSubmit(email);
        setIsSuccess(true);
        setEmail("");
      } catch (error) {
        console.error("Subscription error:", error);
      } finally {
        setIsLoading(false);
      }
    }
  };
 
  return (
    <section
      className={`relative overflow-hidden py-16 sm:py-20 ${styles.section}`}
    >
      <div className="absolute inset-0 bg-[linear-gradient(to_right,#ffffff08_1px,transparent_1px),linear-gradient(to_bottom,#ffffff08_1px,transparent_1px)] bg-[size:24px_24px]" />
      <div className="absolute right-0 top-0 h-64 w-64 rounded-full bg-white/5 blur-3xl" />
      <div className="absolute bottom-0 left-0 h-64 w-64 rounded-full bg-white/5 blur-3xl" />
 
      <div className="container relative mx-auto px-6">
        <div className="mx-auto max-w-4xl">
          <div className="grid gap-8 lg:grid-cols-2 lg:gap-12">
            <div>
              <div className="mb-2 inline-flex items-center gap-2 rounded-full bg-white/10 px-3 py-1">
                <Mail className="h-4 w-4 text-white" />
                <span className="text-sm font-medium text-white">
                  Newsletter
                </span>
              </div>
 
              <h2
                className={`mb-4 text-3xl font-bold tracking-tight sm:text-4xl ${styles.headline}`}
              >
                {headline}
              </h2>
 
              {description && (
                <p className={`mb-6 text-lg ${styles.description}`}>
                  {description}
                </p>
              )}
 
              {benefits && benefits.length > 0 && (
                <ul className="space-y-3">
                  {benefits.map((benefit, index) => (
                    <li key={index} className="flex items-start gap-3">
                      <div
                        className={`mt-0.5 flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full ${styles.checkmark}`}
                      >
                        <Check className="h-3.5 w-3.5 stroke-[3]" />
                      </div>
                      <span className={`text-base ${styles.benefits}`}>
                        {benefit}
                      </span>
                    </li>
                  ))}
                </ul>
              )}
            </div>
 
            <div className="flex items-center">
              <div className="w-full">
                {isSuccess ? (
                  <div
                    className={`animate-in fade-in slide-in-from-bottom-4 rounded-2xl p-8 text-center duration-500 ${styles.successBg}`}
                  >
                    <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-white/20">
                      <Check className="h-8 w-8 text-white" />
                    </div>
                    <h3 className="mb-2 text-xl font-bold text-white">
                      You're all set!
                    </h3>
                    <p className="text-white/80">{successMessage}</p>
                  </div>
                ) : (
                  <form onSubmit={handleSubmit} className="space-y-4">
                    <div className="space-y-3">
                      <Input
                        type="email"
                        placeholder={placeholder}
                        value={email}
                        onChange={(e) => setEmail(e.target.value)}
                        required
                        disabled={isLoading}
                        className={`h-12 text-base transition-all duration-200 ${styles.input}`}
                      />
                      <Button
                        type="submit"
                        size="lg"
                        disabled={isLoading}
                        className={`w-full font-semibold transition-all duration-200 ${styles.button}`}
                      >
                        {isLoading ? (
                          <>
                            <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                            Subscribing...
                          </>
                        ) : (
                          buttonText
                        )}
                      </Button>
                    </div>
                    <p className="text-center text-sm text-white/60">
                      No spam. Unsubscribe anytime.
                    </p>
                  </form>
                )}
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

Update the import paths to match your project setup.

import { Input } from "@/components/ui/input";

Usage

Basic Usage

import NewsletterSignup from "@/components/ui/newsletter-signup";
 
export default function Page() {
  return (
    <NewsletterSignup
      headline="Stay in the loop"
      description="Get weekly updates delivered to your inbox."
      onSubmit={(email) => console.log("Subscribed:", email)}
    />
  );
}

With Benefits List

<NewsletterSignup
  headline="Join our community"
  description="Subscribe to get insider updates."
  benefits={[
    "Weekly curated content",
    "Exclusive tips and tricks",
    "Early access to new features",
  ]}
  onSubmit={(email) => console.log(email)}
/>

Color Variants

{/* Blue - Professional and trustworthy */}
<NewsletterSignup
  variant="blue"
  headline="Stay in the loop"
  onSubmit={(email) => console.log(email)}
/>
 
{/* Purple - Creative and modern */}
<NewsletterSignup
  variant="purple"
  headline="Join our community"
  onSubmit={(email) => console.log(email)}
/>
 
{/* Green - Growth and success */}
<NewsletterSignup
  variant="green"
  headline="Get weekly insights"
  onSubmit={(email) => console.log(email)}
/>
 
{/* Orange - Energetic and bold */}
<NewsletterSignup
  variant="orange"
  headline="Never miss an update"
  onSubmit={(email) => console.log(email)}
/>

Custom Text

<NewsletterSignup
  headline="Join 10,000+ subscribers"
  description="Get actionable tips every week."
  placeholder="you@example.com"
  buttonText="Sign Me Up"
  onSubmit={(email) => console.log(email)}
/>

With API Integration

"use client";
 
import { useState } from "react";
import NewsletterSignup from "@/components/ui/newsletter-signup";
 
export default function Page() {
  const [isLoading, setIsLoading] = useState(false);
 
  const handleSubmit = async (email: string) => {
    setIsLoading(true);
    try {
      const response = await fetch("/api/newsletter", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email }),
      });
      
      if (response.ok) {
        alert("Successfully subscribed!");
      }
    } catch (error) {
      console.error("Subscription failed:", error);
    } finally {
      setIsLoading(false);
    }
  };
 
  return (
    <NewsletterSignup
      headline="Stay updated"
      onSubmit={handleSubmit}
    />
  );
}

Props

PropTypeDefaultDescription
headlinestringRequiredMain headline text
descriptionstringundefinedOptional description
benefitsstring[]undefinedList of benefits with checkmarks
variant"blue" | "purple" | "green" | "orange""blue"Color theme
placeholderstring"Enter your email"Input placeholder text
buttonTextstring"Subscribe"Submit button text
onSubmit(email: string) => voidundefinedForm submit handler

TypeScript Interface

interface NewsletterSignupProps {
  headline: string;
  description?: string;
  benefits?: string[];
  variant?: "blue" | "purple" | "green" | "orange";
  placeholder?: string;
  buttonText?: string;
  onSubmit?: (email: string) => void;
}

Color Psychology

Blue (variant="blue")

  • Trust, professionalism, reliability
  • Best for: B2B, finance, tech companies

Purple (variant="purple")

  • Creativity, luxury, innovation
  • Best for: Creative agencies, premium products

Green (variant="green")

  • Growth, health, success
  • Best for: Sustainability, wellness, finance

Orange (variant="orange")

  • Energy, enthusiasm, action
  • Best for: E-commerce, events, startups

Customization

Add Loading State

const [isLoading, setIsLoading] = useState(false);
 
<Button
  type="submit"
  disabled={isLoading}
  className={styles.button}
>
  {isLoading ? "Subscribing..." : buttonText}
</Button>

Success Message

const [isSubscribed, setIsSubscribed] = useState(false);
 
{isSubscribed ? (
  <div className="text-center text-white">
    <Check className="mx-auto h-12 w-12 mb-2" />
    <p>Thanks for subscribing!</p>
  </div>
) : (
  <form onSubmit={handleSubmit}>
    {/* form content */}
  </form>
)}

Custom Colors

Add your own variant to the variants object:

const variants = {
  // ... existing variants
  custom: {
    section: "bg-pink-600",
    headline: "text-white",
    description: "text-pink-100",
    benefits: "text-pink-50",
    input: "bg-white/10 border-white/20 text-white placeholder:text-white/60",
    button: "bg-white text-pink-600 hover:bg-pink-50",
    checkmark: "bg-white/20 text-white",
  },
};

Use Cases

Perfect for:

  • Blog subscriptions
  • Product updates
  • Weekly newsletters
  • Marketing campaigns
  • Lead generation
  • Community building
  • Event notifications
  • Course enrollments