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