Newsletter section
The whole newsletter band: heading, copy, a form slot and fine print.
npx shadcn@latest add https://ui.goodtabs.co/r/newsletter-section.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/newsletter-section
Newsletter
One email a week
Five tabs worth keeping open, picked by a person.
No spam. Leave with one click.
Heading, support copy and an email signup, centered.
Left aligned
Newsletter
New components, every Friday
A short note on what shipped, with the code and one thing worth reading.
About 600 designers and engineers read it. Leave any time.
Left aligned for a page column, with a custom button label.
Usage
import { NewsletterSection } from "@/components/newsletter-section"
import { EmailSignup } from "@/components/ui/email-signup"
<NewsletterSection title="One email a week" note="Leave with one click.">
<EmailSignup align="center" />
</NewsletterSection>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | string | Small uppercase line above the title. | |
| title | ReactNode | The headline. | |
| description | ReactNode | What lands in the inbox and how often. | |
| note | ReactNode | Fine print under the form. | |
| align | "center" | "left" | "center" | Centered for a footer band. |
| size | "sm" | "default" | "default" | Spacing scale. sm fits a card. |
| children | ReactNode | The form. Pass an EmailSignup or your own. |
Source
newsletter-section/newsletter-section.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
type NewsletterSectionProps = Omit<React.ComponentProps<"section">, "title"> & {
/** Small uppercase line above the title. */
eyebrow?: string;
/** The headline. */
title: React.ReactNode;
/** One or two sentences on what lands in the inbox and how often. */
description?: React.ReactNode;
/** The fine print under the form, for example how to leave. */
note?: React.ReactNode;
/** Centered for a footer band, left for a page column. */
align?: "center" | "left";
/** Spacing scale. "sm" fits a card or narrow column. */
size?: "sm" | "default";
/** The form. Pass an EmailSignup, or your own. */
children: React.ReactNode;
};
/**
* The whole newsletter band: heading, support copy, your form and a line of fine print.
* Server component. The form is a slot, so the field, validation and submit stay in EmailSignup.
*/
export function NewsletterSection({
eyebrow,
title,
description,
note,
align = "center",
size = "default",
children,
className,
...props
}: NewsletterSectionProps) {
const centered = align === "center";
const sm = size === "sm";
return (
<section className={cn(sm ? "py-8" : "py-16 lg:py-24", className)} {...props}>
<div className="mx-auto w-full max-w-6xl px-4 md:px-6">
<div
className={cn(
"flex flex-col gap-4",
centered ? "mx-auto max-w-xl items-center text-center" : "max-w-xl items-start text-left",
)}
>
{eyebrow && <p className="m-0 font-mono text-xs tracking-wide text-muted-foreground uppercase">{eyebrow}</p>}
<h2 className={cn("m-0 font-medium tracking-tight text-balance", sm ? "text-xl" : "text-3xl sm:text-4xl")}>
{title}
</h2>
{description && <p className="m-0 text-sm text-muted-foreground sm:text-base">{description}</p>}
<div className="w-full pt-1">{children}</div>
{note && <p className="m-0 text-xs text-muted-foreground">{note}</p>}
</div>
</div>
</section>
);
}
For AI agents
Hand your agent this page, the markdown at /components/newsletter-section/prompt.md, or the Copy AI prompt button above.
When to use
- Above a footer or at the end of an article
- When the signup needs a heading and promise around it
When not to use
- For a single inline field, use email-signup alone
- For a full contact form, use contact-section
Agent notes
- Server component. The form is the children slot; it reuses email-signup, so install that item too
- Pass align="center" to EmailSignup when the section is centered
- Because email-signup is a client component, any onSubmit handler you pass needs a client wrapper