New: 149+ components, Page Builder, and more
AI App Building Blocks for the Web
Clean, modern building blocks. Copy and paste into your apps. Works with all React frameworks. Open Source. Free forever.
Clean, modern building blocks. Copy and paste into your apps. Works with all React frameworks. Open Source. Free forever.
"use client"
import * as React from "react"
import { Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Input } from "@/components/ui/input"
export function NewsletterBlock() {
const [email, setEmail] = React.useState("")
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubscribed, setIsSubscribed] = React.useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000))
setIsSubscribed(true)
setIsSubmitting(false)
setEmail("")
// Reset success message after 3 seconds
setTimeout(() => setIsSubscribed(false), 3000)
}
return (
<div className="flex min-h-screen items-center justify-center p-4">
<Card className="w-full max-w-md">
<form onSubmit={handleSubmit}>
<CardHeader className="space-y-1 text-center">
<div className="mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
<Mail className="h-6 w-6 text-primary" />
</div>
<CardTitle className="text-2xl">
Subscribe to our newsletter
</CardTitle>
<CardDescription>
Get the latest updates, articles, and resources delivered to your
inbox weekly.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Input
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isSubmitting}
/>
</div>
<Button
type="submit"
className="w-full"
disabled={isSubmitting || isSubscribed}
>
{isSubmitting
? "Subscribing..."
: isSubscribed
? "Subscribed! ✓"
: "Subscribe"}
</Button>
{isSubscribed && (
<p className="text-center text-sm text-muted-foreground">
Thank you for subscribing!
</p>
)}
<p className="text-center text-xs text-muted-foreground">
By subscribing, you agree to our Terms of Service and Privacy
Policy.
</p>
</CardContent>
</form>
</Card>
</div>
)
}


"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function NewsletterBlock() {
const [email, setEmail] = React.useState("")
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubscribed, setIsSubscribed] = React.useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
await new Promise((resolve) => setTimeout(resolve, 1000))
setIsSubscribed(true)
setIsSubmitting(false)
setEmail("")
setTimeout(() => setIsSubscribed(false), 3000)
}
return (
<section className="flex min-h-screen items-center justify-center bg-muted/30 p-4">
<div className="w-full max-w-4xl">
<form onSubmit={handleSubmit} className="space-y-4 text-center">
<div className="space-y-2">
<h2 className="text-3xl font-bold tracking-tight">Stay Updated</h2>
<p className="text-muted-foreground">
Join our newsletter for the latest updates and exclusive content.
</p>
</div>
<div className="mx-auto flex max-w-md gap-2">
<Input
type="email"
placeholder="your@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isSubmitting}
className="flex-1"
/>
<Button
type="submit"
disabled={isSubmitting || isSubscribed}
className="min-w-[120px]"
>
{isSubmitting
? "Subscribing..."
: isSubscribed
? "Subscribed! ✓"
: "Subscribe"}
</Button>
</div>
{isSubscribed && (
<p className="text-sm text-muted-foreground">
Thank you! Check your inbox to confirm.
</p>
)}
</form>
</div>
</section>
)
}


"use client"
import * as React from "react"
import { Check, Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function NewsletterBlock() {
const [email, setEmail] = React.useState("")
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubscribed, setIsSubscribed] = React.useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
await new Promise((resolve) => setTimeout(resolve, 1000))
setIsSubscribed(true)
setIsSubmitting(false)
setEmail("")
setTimeout(() => setIsSubscribed(false), 3000)
}
return (
<section className="flex min-h-screen items-center justify-center p-4 md:p-8">
<div className="grid w-full max-w-6xl gap-8 lg:grid-cols-2 lg:gap-12">
{/* Left side - Content */}
<div className="flex flex-col justify-center space-y-6">
<div className="space-y-2">
<h2 className="text-4xl font-bold tracking-tight sm:text-5xl">
Join Our Newsletter
</h2>
<p className="text-xl text-muted-foreground">
Get weekly insights, tips, and exclusive content delivered
directly to your inbox.
</p>
</div>
<ul className="space-y-3">
{[
"Weekly curated content",
"Exclusive subscriber-only resources",
"Early access to new features",
"Unsubscribe anytime",
].map((feature, i) => (
<li key={i} className="flex items-center gap-3">
<div className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary/10">
<Check className="h-4 w-4 text-primary" />
</div>
<span>{feature}</span>
</li>
))}
</ul>
</div>
{/* Right side - Form */}
<div className="flex flex-col justify-center">
<div className="rounded-lg border bg-card p-8 shadow-sm">
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium">
Email address
</label>
<Input
id="email"
type="email"
placeholder="you@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isSubmitting}
/>
</div>
<Button
type="submit"
className="w-full"
size="lg"
disabled={isSubmitting || isSubscribed}
>
<Mail className="mr-2 h-4 w-4" />
{isSubmitting
? "Subscribing..."
: isSubscribed
? "Subscribed! ✓"
: "Subscribe Now"}
</Button>
{isSubscribed && (
<p className="text-center text-sm text-muted-foreground">
Success! Check your email to confirm.
</p>
)}
<p className="text-center text-xs text-muted-foreground">
By subscribing, you agree to our Terms and Privacy Policy.
</p>
</form>
</div>
</div>
</div>
</section>
)
}


"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function NewsletterBlock() {
const [email, setEmail] = React.useState("")
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubscribed, setIsSubscribed] = React.useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
await new Promise((resolve) => setTimeout(resolve, 1000))
setIsSubscribed(true)
setIsSubmitting(false)
setEmail("")
setTimeout(() => setIsSubscribed(false), 3000)
}
return (
<section className="flex min-h-screen items-center justify-center p-4">
<div className="w-full max-w-2xl space-y-6 text-center">
<div className="space-y-3">
<h1 className="text-5xl font-bold tracking-tight sm:text-6xl md:text-7xl">
Subscribe
</h1>
<p className="mx-auto max-w-lg text-lg text-muted-foreground sm:text-xl">
Get notified about new articles, tutorials, and product updates.
</p>
</div>
<form onSubmit={handleSubmit} className="mx-auto max-w-md">
<div className="flex gap-2">
<Input
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isSubmitting}
className="h-12 text-base"
/>
<Button
type="submit"
size="lg"
disabled={isSubmitting || isSubscribed}
className="min-w-[100px]"
>
{isSubmitting ? "..." : isSubscribed ? "✓" : "Join"}
</Button>
</div>
{isSubscribed && (
<p className="mt-3 text-sm text-muted-foreground">
You're in! Check your email.
</p>
)}
</form>
</div>
</section>
)
}


"use client"
import * as React from "react"
import { ArrowRight } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function NewsletterBlock() {
const [email, setEmail] = React.useState("")
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [isSubscribed, setIsSubscribed] = React.useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsSubmitting(true)
await new Promise((resolve) => setTimeout(resolve, 1000))
setIsSubscribed(true)
setIsSubmitting(false)
setEmail("")
setTimeout(() => setIsSubscribed(false), 3000)
}
return (
<section className="flex min-h-screen items-center justify-center">
<div className="w-full bg-primary px-4 py-16 text-primary-foreground sm:px-6 lg:px-8">
<div className="mx-auto max-w-7xl">
<div className="grid gap-8 lg:grid-cols-2 lg:gap-12 lg:items-center">
{/* Content */}
<div className="space-y-4">
<div className="inline-block rounded-full bg-primary-foreground/10 px-3 py-1 text-sm font-medium">
Newsletter
</div>
<h2 className="text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
Never miss an update
</h2>
<p className="text-lg text-primary-foreground/90 sm:text-xl">
Join thousands of subscribers getting exclusive insights,
tutorials, and early access to new features.
</p>
</div>
{/* Form */}
<div className="lg:pl-8">
<form onSubmit={handleSubmit} className="space-y-4">
<div className="flex flex-col gap-3 sm:flex-row">
<Input
type="email"
placeholder="your@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={isSubmitting}
className="h-12 flex-1 border-primary-foreground/20 bg-primary-foreground/10 text-primary-foreground placeholder:text-primary-foreground/60"
/>
<Button
type="submit"
size="lg"
disabled={isSubmitting || isSubscribed}
variant="secondary"
className="sm:min-w-[140px]"
>
{isSubmitting ? (
"Subscribing..."
) : isSubscribed ? (
"Subscribed! ✓"
) : (
<>
Subscribe
<ArrowRight className="ml-2 h-4 w-4" />
</>
)}
</Button>
</div>
{isSubscribed && (
<p className="text-sm text-primary-foreground/90">
Welcome aboard! Confirmation email sent.
</p>
)}
<p className="text-xs text-primary-foreground/70">
We respect your privacy. Unsubscribe at any time.
</p>
</form>
</div>
</div>
</div>
</div>
</section>
)
}

