- Learn
- Guided Projects
- Build a SaaS Landing Page
Beginner40 min1 prerequisite
Create a professional SaaS landing page with hero sections, feature grids, pricing tables, and testimonials.
Build a SaaS Landing Page
Create a conversion-optimized SaaS landing page with modern design patterns, responsive layouts, and interactive elements.
Project Overview
What We're Building
Terminal
Landing Page Sections:
├── Hero Section
│ ├── Headline + subheadline
│ ├── CTA buttons
│ └── Product screenshot/demo
├── Social Proof
│ └── Logo cloud + stats
├── Features Grid
│ ├── Icon + title + description
│ └── 6-9 features
├── How It Works
│ └── 3-step process
├── Pricing Table
│ ├── 3 tiers (Free/Pro/Enterprise)
│ └── Feature comparison
├── Testimonials
│ └── Customer quotes + avatars
├── FAQ Section
│ └── Accordion items
└── Footer CTA
└── Final conversion push
Tech Stack
- Framework: Next.js + Tailwind
- Components: shadcn/ui
- Animations: Framer Motion (optional)
- Icons: Lucide React
Phase 1: Project Setup
Create Project
Terminal
npx create-next-app@latest saas-landing --typescript --tailwind --eslint
cd saas-landing
# Add shadcn/ui
npx shadcn@latest init
# Add components
npx shadcn@latest add button card badge accordion tabs
# Optional: Add animations
npm install framer-motion
AI Prompt for Full Page
Terminal
"Create a SaaS landing page for an AI writing assistant.
Include these sections:
1. Hero with headline, subheadline, and CTA buttons
2. Logo cloud showing trusted companies
3. Features grid (6 features with icons)
4. How it works (3 steps)
5. Pricing table (3 tiers)
6. Testimonials (3 customer quotes)
7. FAQ accordion
8. Footer with CTA
Use Next.js, Tailwind, and shadcn/ui.
Make it responsive and professional."
Phase 2: Hero Section
AI Prompt for Hero
Terminal
"Create a hero section component with:
- Large headline with gradient text
- Subheadline explaining the value prop
- Two CTA buttons (primary and secondary)
- Product screenshot or illustration placeholder
- Responsive: stack on mobile, side-by-side on desktop"
Hero Component
Terminal
// components/Hero.tsx
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { ArrowRight, Play } from 'lucide-react'
export function Hero() {
return (
<section className="relative py-20 lg:py-32 overflow-hidden">
{/* Background gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-background to-background" />
<div className="container relative mx-auto px-4">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Text content */}
<div className="text-center lg:text-left">
<div className="inline-block px-4 py-1.5 mb-6 text-sm font-medium rounded-full bg-primary/10 text-primary">
✨ Now with AI-powered suggestions
</div>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight mb-6">
Write better content{' '}
<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-purple-600">
10x faster
</span>
</h1>
<p className="text-xl text-muted-foreground mb-8 max-w-lg mx-auto lg:mx-0">
AI-powered writing assistant that helps you create engaging
content, fix grammar, and maintain your unique voice.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
<Button size="lg" asChild>
<Link href="/signup">
Start Free Trial
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button size="lg" variant="outline" asChild>
<Link href="/demo">
<Play className="mr-2 h-4 w-4" />
Watch Demo
</Link>
</Button>
</div>
<p className="mt-4 text-sm text-muted-foreground">
No credit card required • 14-day free trial
</p>
</div>
{/* Product image */}
<div className="relative">
<div className="relative rounded-xl border bg-muted/50 shadow-2xl overflow-hidden">
<img
src="/product-screenshot.png"
alt="Product screenshot"
className="w-full"
/>
</div>
{/* Decorative elements */}
<div className="absolute -z-10 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[120%] h-[120%] bg-gradient-to-r from-primary/20 to-purple-500/20 blur-3xl rounded-full" />
</div>
</div>
</div>
</section>
)
}
Phase 3: Social Proof
Logo Cloud
Terminal
// components/LogoCloud.tsx
export function LogoCloud() {
const logos = [
{ name: 'Company 1', src: '/logos/company1.svg' },
{ name: 'Company 2', src: '/logos/company2.svg' },
{ name: 'Company 3', src: '/logos/company3.svg' },
{ name: 'Company 4', src: '/logos/company4.svg' },
{ name: 'Company 5', src: '/logos/company5.svg' },
]
return (
<section className="py-12 border-y bg-muted/30">
<div className="container mx-auto px-4">
<p className="text-center text-sm text-muted-foreground mb-8">
Trusted by 10,000+ teams at
</p>
<div className="flex flex-wrap justify-center items-center gap-8 md:gap-16">
{logos.map((logo) => (
<img
key={logo.name}
src={logo.src}
alt={logo.name}
className="h-8 opacity-50 hover:opacity-100 transition-opacity"
/>
))}
</div>
</div>
</section>
)
}
Stats Section
Terminal
// components/Stats.tsx
export function Stats() {
const stats = [
{ value: '10K+', label: 'Active Users' },
{ value: '50M+', label: 'Words Generated' },
{ value: '99.9%', label: 'Uptime' },
{ value: '4.9/5', label: 'User Rating' },
]
return (
<section className="py-16">
<div className="container mx-auto px-4">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{stats.map((stat) => (
<div key={stat.label} className="text-center">
<div className="text-4xl font-bold text-primary mb-2">
{stat.value}
</div>
<div className="text-sm text-muted-foreground">
{stat.label}
</div>
</div>
))}
</div>
</div>
</section>
)
}
Phase 4: Features Grid
AI Prompt for Features
Terminal
"Create a features section with a 3-column grid.
Each feature card should have:
- Icon in a colored circle
- Feature title
- Short description
Include 6 features for an AI writing tool:
1. AI Writing Assistant
2. Grammar Correction
3. Tone Adjustment
4. Plagiarism Check
5. Multi-language Support
6. Team Collaboration"
Features Component
Terminal
// components/Features.tsx
import { Card, CardContent } from '@/components/ui/card'
import {
Sparkles,
CheckCircle,
Sliders,
Shield,
Globe,
Users
} from 'lucide-react'
const features = [
{
icon: Sparkles,
title: 'AI Writing Assistant',
description: 'Generate high-quality content in seconds with our advanced AI models.',
color: 'text-purple-500 bg-purple-500/10'
},
{
icon: CheckCircle,
title: 'Grammar Correction',
description: 'Automatically fix grammar, spelling, and punctuation errors.',
color: 'text-green-500 bg-green-500/10'
},
{
icon: Sliders,
title: 'Tone Adjustment',
description: 'Adapt your writing style from casual to professional instantly.',
color: 'text-blue-500 bg-blue-500/10'
},
{
icon: Shield,
title: 'Plagiarism Check',
description: 'Ensure your content is original with built-in plagiarism detection.',
color: 'text-red-500 bg-red-500/10'
},
{
icon: Globe,
title: 'Multi-language',
description: 'Write and translate content in over 30 languages.',
color: 'text-orange-500 bg-orange-500/10'
},
{
icon: Users,
title: 'Team Collaboration',
description: 'Work together with shared workspaces and real-time editing.',
color: 'text-cyan-500 bg-cyan-500/10'
},
]
export function Features() {
return (
<section className="py-20">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4">
Everything you need to write better
</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Powerful features that help you create content faster without
sacrificing quality.
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{features.map((feature) => (
<Card key={feature.title} className="border-0 shadow-none bg-muted/50">
<CardContent className="pt-6">
<div className={`w-12 h-12 rounded-lg flex items-center justify-center mb-4 ${feature.color}`}>
<feature.icon className="h-6 w-6" />
</div>
<h3 className="text-xl font-semibold mb-2">{feature.title}</h3>
<p className="text-muted-foreground">{feature.description}</p>
</CardContent>
</Card>
))}
</div>
</div>
</section>
)
}
Phase 5: Pricing Table
AI Prompt for Pricing
Terminal
"Create a pricing section with 3 tiers:
- Free: $0, basic features
- Pro: $19/month, all features
- Enterprise: Custom pricing, advanced features
Highlight the Pro plan as 'Most Popular'.
Include a feature list for each tier.
Add monthly/yearly toggle with 20% discount for yearly."
Pricing Component
Terminal
// components/Pricing.tsx
'use client'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Check } from 'lucide-react'
const plans = [
{
name: 'Free',
price: { monthly: 0, yearly: 0 },
description: 'Perfect for trying out',
features: [
'5,000 words/month',
'Basic grammar check',
'3 tone options',
'Email support',
],
cta: 'Get Started',
popular: false,
},
{
name: 'Pro',
price: { monthly: 19, yearly: 15 },
description: 'Best for professionals',
features: [
'Unlimited words',
'Advanced AI writing',
'All tone options',
'Plagiarism checker',
'Priority support',
'API access',
],
cta: 'Start Free Trial',
popular: true,
},
{
name: 'Enterprise',
price: { monthly: null, yearly: null },
description: 'For large teams',
features: [
'Everything in Pro',
'Custom AI training',
'SSO & SAML',
'Dedicated account manager',
'SLA guarantee',
'Custom integrations',
],
cta: 'Contact Sales',
popular: false,
},
]
export function Pricing() {
const [isYearly, setIsYearly] = useState(false)
return (
<section className="py-20 bg-muted/30">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl font-bold mb-4">
Simple, transparent pricing
</h2>
<p className="text-xl text-muted-foreground mb-8">
Choose the plan that's right for you
</p>
{/* Billing toggle */}
<div className="flex items-center justify-center gap-4">
<span className={!isYearly ? 'font-medium' : 'text-muted-foreground'}>
Monthly
</span>
<button
onClick={() => setIsYearly(!isYearly)}
className={`relative w-14 h-7 rounded-full transition-colors ${
isYearly ? 'bg-primary' : 'bg-muted'
}`}
>
<span
className={`absolute top-1 w-5 h-5 rounded-full bg-white transition-transform ${
isYearly ? 'translate-x-8' : 'translate-x-1'
}`}
/>
</button>
<span className={isYearly ? 'font-medium' : 'text-muted-foreground'}>
Yearly
<Badge variant="secondary" className="ml-2">Save 20%</Badge>
</span>
</div>
</div>
<div className="grid md:grid-cols-3 gap-8 max-w-5xl mx-auto">
{plans.map((plan) => (
<Card
key={plan.name}
className={`relative ${
plan.popular ? 'border-primary shadow-lg scale-105' : ''
}`}
>
{plan.popular && (
<Badge className="absolute -top-3 left-1/2 -translate-x-1/2">
Most Popular
</Badge>
)}
<CardHeader>
<CardTitle>{plan.name}</CardTitle>
<p className="text-sm text-muted-foreground">{plan.description}</p>
</CardHeader>
<CardContent>
<div className="mb-6">
{plan.price.monthly !== null ? (
<>
<span className="text-4xl font-bold">
${isYearly ? plan.price.yearly : plan.price.monthly}
</span>
<span className="text-muted-foreground">/month</span>
</>
) : (
<span className="text-4xl font-bold">Custom</span>
)}
</div>
<ul className="space-y-3">
{plan.features.map((feature) => (
<li key={feature} className="flex items-center gap-2">
<Check className="h-4 w-4 text-primary" />
<span className="text-sm">{feature}</span>
</li>
))}
</ul>
</CardContent>
<CardFooter>
<Button
className="w-full"
variant={plan.popular ? 'default' : 'outline'}
>
{plan.cta}
</Button>
</CardFooter>
</Card>
))}
</div>
</div>
</section>
)
}
Phase 6: Testimonials
Testimonials Component
Terminal
// components/Testimonials.tsx
import { Card, CardContent } from '@/components/ui/card'
const testimonials = [
{
quote: "This tool has completely transformed how I write. I'm now 3x more productive.",
author: 'Sarah Chen',
role: 'Content Marketing Manager',
company: 'TechCorp',
avatar: '/avatars/sarah.jpg',
},
{
quote: "The AI suggestions are incredibly accurate. It's like having a professional editor on call 24/7.",
author: 'Michael Roberts',
role: 'Freelance Writer',
company: 'Self-employed',
avatar: '/avatars/michael.jpg',
},
{
quote: "We rolled this out to our entire content team. The ROI was immediate.",
author: 'Emily Watson',
role: 'VP of Marketing',
company: 'StartupXYZ',
avatar: '/avatars/emily.jpg',
},
]
export function Testimonials() {
return (
<section className="py-20">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4">
Loved by writers everywhere
</h2>
<p className="text-xl text-muted-foreground">
See what our customers have to say
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
{testimonials.map((testimonial) => (
<Card key={testimonial.author}>
<CardContent className="pt-6">
<div className="flex gap-1 mb-4">
{[...Array(5)].map((_, i) => (
<span key={i} className="text-yellow-500">★</span>
))}
</div>
<blockquote className="text-lg mb-6">
"{testimonial.quote}"
</blockquote>
<div className="flex items-center gap-3">
<img
src={testimonial.avatar}
alt={testimonial.author}
className="w-10 h-10 rounded-full"
/>
<div>
<div className="font-medium">{testimonial.author}</div>
<div className="text-sm text-muted-foreground">
{testimonial.role}, {testimonial.company}
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
</section>
)
}
Phase 7: FAQ Section
FAQ Component
Terminal
// components/FAQ.tsx
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion'
const faqs = [
{
question: 'How does the AI writing assistant work?',
answer: 'Our AI uses advanced language models to understand context and generate human-like text. Simply start typing or provide a prompt, and the AI will suggest completions, improvements, or entirely new content.',
},
{
question: 'Is my content secure and private?',
answer: 'Yes, absolutely. We use enterprise-grade encryption and never store your content longer than necessary. Your data is never used to train our models.',
},
{
question: 'Can I cancel my subscription anytime?',
answer: 'Yes, you can cancel your subscription at any time. If you cancel, you\'ll continue to have access until the end of your billing period.',
},
{
question: 'Do you offer a free trial?',
answer: 'Yes! All new users get a 14-day free trial of our Pro plan. No credit card required to start.',
},
{
question: 'What languages are supported?',
answer: 'We currently support over 30 languages including English, Spanish, French, German, Portuguese, Japanese, Chinese, and more.',
},
]
export function FAQ() {
return (
<section className="py-20 bg-muted/30">
<div className="container mx-auto px-4 max-w-3xl">
<div className="text-center mb-12">
<h2 className="text-3xl md:text-4xl font-bold mb-4">
Frequently asked questions
</h2>
<p className="text-xl text-muted-foreground">
Everything you need to know about the product
</p>
</div>
<Accordion type="single" collapsible className="w-full">
{faqs.map((faq, index) => (
<AccordionItem key={index} value={`item-${index}`}>
<AccordionTrigger className="text-left">
{faq.question}
</AccordionTrigger>
<AccordionContent className="text-muted-foreground">
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
</section>
)
}
Phase 8: Footer CTA
CTA Component
Terminal
// components/FooterCTA.tsx
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { ArrowRight } from 'lucide-react'
export function FooterCTA() {
return (
<section className="py-20">
<div className="container mx-auto px-4">
<div className="relative overflow-hidden rounded-3xl bg-primary px-6 py-20 text-center text-primary-foreground">
{/* Background decoration */}
<div className="absolute inset-0 bg-gradient-to-br from-primary to-purple-700" />
<div className="absolute top-0 left-1/4 w-96 h-96 bg-white/10 rounded-full blur-3xl" />
<div className="absolute bottom-0 right-1/4 w-96 h-96 bg-white/10 rounded-full blur-3xl" />
<div className="relative">
<h2 className="text-3xl md:text-5xl font-bold mb-6">
Ready to write smarter?
</h2>
<p className="text-xl opacity-90 mb-8 max-w-2xl mx-auto">
Join thousands of writers who are already creating better content
in less time.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Button size="lg" variant="secondary" asChild>
<Link href="/signup">
Start Your Free Trial
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
<Button size="lg" variant="outline" className="bg-transparent border-white/30 hover:bg-white/10" asChild>
<Link href="/demo">
Schedule a Demo
</Link>
</Button>
</div>
</div>
</div>
</div>
</section>
)
}
Putting It All Together
Homepage
Terminal
// app/page.tsx
import { Hero } from '@/components/Hero'
import { LogoCloud } from '@/components/LogoCloud'
import { Stats } from '@/components/Stats'
import { Features } from '@/components/Features'
import { Pricing } from '@/components/Pricing'
import { Testimonials } from '@/components/Testimonials'
import { FAQ } from '@/components/FAQ'
import { FooterCTA } from '@/components/FooterCTA'
export default function HomePage() {
return (
<main>
<Hero />
<LogoCloud />
<Stats />
<Features />
<Pricing />
<Testimonials />
<FAQ />
<FooterCTA />
</main>
)
}
Verification Checklist
- Hero section renders correctly
- All sections are responsive
- Pricing toggle works
- FAQ accordion expands/collapses
- CTA buttons link correctly
- Images load properly
- Dark mode works
- Page loads quickly
Extensions
Once working, try adding:
- Animated scroll effects with Framer Motion
- Live chat widget
- Newsletter signup form
- Blog integration
- Customer case studies
- Product comparison tables
- Video testimonials
Summary
You built a SaaS landing page with:
- Hero section with gradient text and CTA
- Social proof elements
- Feature grid with icons
- Interactive pricing table
- Customer testimonials
- FAQ accordion
- Footer CTA section
Next Steps
Build a complete authentication system with multiple providers and protected routes.
Mark this lesson as complete to track your progress