shadcn/ui is a collection of re-usable components that you can copy and paste into your apps. You can install different shadcn/ui components and use them to create a subscription component for your newsletter.
To use the examples below, you'll need to install the Card, Button, Input, and Label components:
npx shadcn-ui@latest add button card input label
You may notice that we do not install the Form
component. That's intentional; shadcn's form boilerplate pulls in React Hook Form and Zod, both of which are great libraries but overkill for simple subscription forms. If you've already installed them and want to use them, you can, but use the URL shown in the examples below for the action
prop of Form
.
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function SubscribeForm() {
return (
<Card className="w-full max-w-sm mx-auto">
<form
action="
https://buttondown.com/api/emails/embed-subscribe/YOUR-BUTTONDOWN-USERNAME
"
method="post"
>
<CardHeader>
<CardTitle className="text-2xl">Stay informed</CardTitle>
<CardDescription>
You'll be the first to know when we launch.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
/>
</div>
</CardContent>
<CardFooter>
<Button className="w-full" type="submit">
Subscribe
</Button>
</CardFooter>
</form>
</Card>
);
}
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useState } from "react";
export default function SubscribeForm() {
const [language, setLanguage] = useState("english");
return (
<Card className="w-full max-w-sm mx-auto shadow-md">
<form
action="
https://buttondown.com/api/emails/embed-subscribe/YOUR-BUTTONDOWN-USERNAME
"
method="post"
>
<CardHeader>
<CardTitle className="text-2xl">Stay informed</CardTitle>
<CardDescription>
You'll be the first to know when we launch.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
/>
</div>
<div className="grid gap-2">
<input type="hidden" name="tag" value={language} />
<Label htmlFor="language">Language</Label>
<Select defaultValue="english" onValueChange={setLanguage}>
<SelectTrigger>
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent>
<SelectItem value="english">English</SelectItem>
<SelectItem value="french">French</SelectItem>
<SelectItem value="spanish">Spanish</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent>
<CardFooter>
<Button className="w-full" type="submit">
{language === "english"
? "Subscribe"
: language === "french"
? "S'abonner"
: "Suscribirse"}
</Button>
</CardFooter>
</form>
</Card>
);
}