All Taste components
CTA
Newsletter signup
A short pitch for a newsletter with an email field and a plain promise about what people will get.
copy + inline form · labelled field · privacy note · stacks on small screens
The Friday ledger
One short email a week on pricing, contracts and getting paid as a freelancer.
"use client";
import { useState } from "react";
import { Mail } from "lucide-react";
export function NewsletterSignup({ onSubscribe }: { onSubscribe: (email: string) => Promise<void> }) {
const [email, setEmail] = useState("");
const [state, setState] = useState<"idle" | "sending" | "done" | "error">("idle");
async function submit(e: React.FormEvent) {
e.preventDefault();
setState("sending");
try { await onSubscribe(email); setState("done"); } catch { setState("error"); }
}
return (
<section aria-labelledby="newsletter-title" className="bg-bg px-4 py-16 font-sans sm:px-6">
<div className="mx-auto grid max-w-6xl items-center gap-8 rounded-xl border border-border bg-surface p-6 sm:p-10 lg:grid-cols-2">
<div>
<span className="inline-grid size-9 place-items-center rounded bg-primary-soft text-primary-soft-fg"><Mail className="size-[18px]" aria-hidden /></span>
<h2 id="newsletter-title" className="mt-4 text-2xl font-semibold tracking-tight text-fg">The Friday ledger</h2>
<p className="mt-2 text-sm leading-relaxed text-fg-muted">One short email a week on pricing, contracts and getting paid as a freelancer.</p>
</div>
<form onSubmit={submit} className="grid gap-2">
<label htmlFor="newsletter-email" className="sr-only">Email address</label>
<div className="flex flex-wrap gap-2">
<input
id="newsletter-email"
type="email"
required
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@studio.com"
className="h-10 min-w-0 flex-1 basis-48 rounded border border-border-strong bg-bg px-3 text-sm text-fg outline-none placeholder:text-fg-subtle focus:border-primary focus:ring-[3px] focus:ring-primary/20"
/>
<button type="submit" disabled={state === "sending"} className="h-10 rounded bg-primary px-4 text-sm font-medium text-primary-fg transition hover:bg-primary-hover disabled:opacity-50">
{state === "sending" ? "Subscribing…" : "Subscribe"}
</button>
</div>
<p role="status" className="text-[13px] text-fg-subtle">
{state === "done" ? "You’re in. Check your inbox to confirm." : state === "error" ? "That didn’t work. Try again in a moment." : "No spam. Unsubscribe in one click."}
</p>
</form>
</div>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.