Newsletter Signup Section
A subscription form section with input animation, a submit-success transformation, and social proof.
A centered newsletter signup section: the email input lights up with a glow on focus, the submit button transforms in turn into a spinning loading circle and then a success checkmark, and a paper plane flies out of the button. Below it, a stack of subscriber avatars plus a headcount provides social proof, and the count ticks up by one the moment a signup succeeds.
Loading preview…
npx shadcn@latest add https://webberui.com/r/newsletter-signup-section.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
12480
3200
<NewsletterSignupSection />
Installation
npx shadcn@latest add https://webberui.com/r/newsletter-signup-section.jsonOr, once registries are configured in components.json, install it as @webberui/newsletter-signup-section.
Usage
import { NewsletterSignupSection } from "@/components/ui/newsletter-signup-section";
<NewsletterSignupSection
title="One email a week, design inspiration straight to your inbox"
subtitle="Handpicked UI animation techniques and frontend trends. Unsubscribe whenever you like."
subscriberCount={12480}
onSubscribe={async (email) => {
await fetch("/api/subscribe", {
method: "POST",
body: JSON.stringify({ email }),
});
}}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | "訂閱我們的電子報" (Subscribe to our newsletter) | The section's main heading |
subtitle | string | "每週精選內容直送信箱,隨時可以取消訂閱。" (Handpicked content straight to your inbox every week. Unsubscribe whenever you like.) | Subheading text |
placeholder | string | "you@example.com" | Placeholder text for the email input |
buttonLabel | string | "訂閱" (Subscribe) | Default text on the submit button |
successLabel | string | "已訂閱" (Subscribed) | Text the button shows after a successful submit |
successMessage | string | "感謝訂閱!確認信已寄往你的信箱。" (Thanks for subscribing! A confirmation email is on its way to your inbox.) | The message shown below the form after success |
subscriberCount | number | 12480 | Total number of subscribers, shown in the social-proof text |
avatars | string[] | ["林","陳","張","王","李"] | The list of initials for the avatar stack; each string renders as one gradient avatar |
onSubscribe | (email: string) => void | Promise<void> | — | Called on submit; on rejection an error is shown and the form returns to its waiting-for-input state |
resetDelay | number | 3200 | Delay before resetting automatically after success (milliseconds); 0 means it stays in the success state |
className | string | — | Forwarded to the outermost section |
Accessibility
- The email input has an
sr-onlylabel,type="email", andautoComplete="email", so browser autofill works - Error and success messages live in an
aria-live="polite"region, so assistive technology announces them right away - On a format error the input is marked
aria-invalidand associated with the error text througharia-describedby - While submitting, the button is marked
aria-busyand disabled, which prevents submitting twice - When the user has "reduce motion" enabled at the system level, the paper plane flight and the error shake animation are disabled, leaving only the fade-in feedback
- The avatar stack is decorative content (
aria-hidden), and the subscriber count is provided as plain text