Docs
Case Study Showcase

Case Study Showcase

Detailed success stories with challenge-solution-results format. Perfect for showcasing customer achievements and building trust.

Success Stories

Customer Success Stories

See how companies are achieving their goals with our platform

Featured
How TechFlow increased productivity by 300%
300%
Productivity Increase
40%
Cost Reduction
20hrs
Time Saved

TechFlow Solutions

SaaSยท50-200 employees

How TechFlow increased productivity by 300%

Learn how TechFlow transformed their workflow and achieved remarkable growth in just 6 months.

DataSync scales to 10M+ users seamlessly
10M+
Users Served
99.99%
Uptime
<50ms
Response Time

DataSync Inc

Data Analyticsยท200-500 employees

DataSync scales to 10M+ users seamlessly

Discover how DataSync handled explosive growth without compromising performance or user experience.

CloudVentures achieves $5M ARR in first year
$5M
Annual Revenue
500+
Customers
$2M
Cost Savings

CloudVentures

Cloud Servicesยท500+ employees

CloudVentures achieves $5M ARR in first year

See how CloudVentures leveraged our platform to rapidly scale their business and achieve profitability.

GrowthLabs reduces churn by 60% with better insights
60%
Churn Reduction
150%
LTV Increase
95%
Satisfaction

GrowthLabs

Marketing Techยท20-50 employees

GrowthLabs reduces churn by 60% with better insights

Learn how GrowthLabs used our analytics to understand their customers and dramatically reduce churn.

Want to be our next success story?

Get Started Today

Installation

Install dependencies

npm install framer-motion lucide-react

Copy and paste the following code into your project.

"use client";
 
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
  ArrowRight,
  TrendingUp,
  Users,
  DollarSign,
  Sparkles,
} from "lucide-react";
 
interface Metric {
  label: string;
  value: string;
  icon: "trending" | "users" | "dollar";
}
 
interface CaseStudy {
  id: string;
  company: {
    name: string;
    logo?: string;
    industry: string;
    size: string;
  };
  title: string;
  description: string;
  challenge: string;
  solution: string;
  results: string;
  metrics: Metric[];
  image?: string;
  link?: string;
  featured?: boolean;
}
 
interface CaseStudyShowcaseProps {
  title?: string;
  description?: string;
  caseStudies: CaseStudy[];
  className?: string;
}
 
const iconMap = {
  trending: TrendingUp,
  users: Users,
  dollar: DollarSign,
};
 
export function CaseStudyShowcase({
  title = "Customer Success Stories",
  description = "See how companies are achieving their goals with our platform",
  caseStudies,
  className = "",
}: CaseStudyShowcaseProps) {
  const [expandedId, setExpandedId] = useState<string | null>(null);
 
  return (
    <section className={`w-full bg-white py-20 dark:bg-black ${className}`}>
      <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
        <div className="mb-20 text-center">
          <motion.div
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            className="mb-4 inline-flex items-center gap-2 rounded-full border border-zinc-200 bg-zinc-50 px-4 py-1.5 text-sm font-medium text-zinc-700 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-300"
          >
            <Sparkles className="h-4 w-4" />
            Success Stories
          </motion.div>
          <motion.h2
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ delay: 0.1 }}
            className="mb-4 text-4xl font-bold text-zinc-900 dark:text-white sm:text-5xl"
          >
            {title}
          </motion.h2>
          <motion.p
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ delay: 0.2 }}
            className="mx-auto max-w-2xl text-lg text-zinc-600 dark:text-zinc-400"
          >
            {description}
          </motion.p>
        </div>
 
        <div className="space-y-8">
          {caseStudies.map((study, index) => {
            const isExpanded = expandedId === study.id;
 
            return (
              <motion.article
                key={study.id}
                initial={{ opacity: 0, y: 20 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ delay: index * 0.1 }}
                className="group relative overflow-hidden rounded-3xl border border-zinc-200 bg-white transition-all duration-500 hover:shadow-2xl dark:border-zinc-800 dark:bg-zinc-950"
                style={{
                  boxShadow: study.featured
                    ? "0 0 0 1px rgba(59, 130, 246, 0.5)"
                    : undefined,
                }}
              >
                {/* Featured Badge */}
                {study.featured && (
                  <div className="absolute left-8 top-8 z-10 flex items-center gap-1.5 rounded-full bg-blue-500 px-3 py-1.5 text-xs font-semibold text-white shadow-lg">
                    <Sparkles className="h-3 w-3" />
                    Featured
                  </div>
                )}
 
                <div className="grid gap-0 lg:grid-cols-5">
                  {study.image && (
                    <div className="relative h-80 overflow-hidden lg:col-span-2 lg:h-auto">
                      <img
                        src={study.image}
                        alt={study.title}
                        className="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
                      />
                      <div className="absolute inset-0 bg-gradient-to-br from-black/40 via-black/20 to-transparent" />
 
                      <div className="absolute bottom-6 left-6 right-6">
                        <div className="grid grid-cols-3 gap-3">
                          {study.metrics.map((metric, idx) => {
                            const Icon = iconMap[metric.icon];
                            return (
                              <motion.div
                                key={idx}
                                initial={{ opacity: 0, y: 20 }}
                                animate={{ opacity: 1, y: 0 }}
                                transition={{ delay: index * 0.1 + idx * 0.1 }}
                                className="rounded-xl border border-white/20 bg-white/10 p-3 text-center backdrop-blur-md"
                              >
                                <Icon className="mx-auto mb-1 h-4 w-4 text-white" />
                                <div className="mb-0.5 text-lg font-bold text-white">
                                  {metric.value}
                                </div>
                                <div className="text-[10px] leading-tight text-white/90">
                                  {metric.label}
                                </div>
                              </motion.div>
                            );
                          })}
                        </div>
                      </div>
                    </div>
                  )}
 
                  <div className="flex flex-col p-8 lg:col-span-3 lg:p-12">
                    <div className="mb-8">
                      <div className="mb-6 flex items-center gap-4">
                        {study.company.logo && (
                          <div className="flex h-14 w-14 items-center justify-center rounded-xl bg-zinc-100 p-2.5 dark:bg-zinc-900">
                            <img
                              src={study.company.logo}
                              alt={study.company.name}
                              className="h-full w-full object-contain"
                            />
                          </div>
                        )}
                        <div>
                          <h3 className="text-xl font-bold text-zinc-900 dark:text-white">
                            {study.company.name}
                          </h3>
                          <div className="flex items-center gap-2 text-sm text-zinc-600 dark:text-zinc-400">
                            <span>{study.company.industry}</span>
                            <span>ยท</span>
                            <span>{study.company.size}</span>
                          </div>
                        </div>
                      </div>
 
                      <h4 className="mb-3 text-3xl font-bold leading-tight text-zinc-900 dark:text-white">
                        {study.title}
                      </h4>
                      <p className="text-base leading-relaxed text-zinc-600 dark:text-zinc-400">
                        {study.description}
                      </p>
                    </div>
 
                    <div className="flex-1">
                      <button
                        onClick={() =>
                          setExpandedId(isExpanded ? null : study.id)
                        }
                        className="mb-4 inline-flex items-center gap-2 text-sm font-semibold text-blue-600 transition-colors hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 cursor-pointer"
                      >
                        {isExpanded ? "Show less" : "Read full story"}
                        <motion.div
                          animate={{ rotate: isExpanded ? 90 : 0 }}
                          transition={{ duration: 0.3 }}
                        >
                          <ArrowRight className="h-4 w-4" />
                        </motion.div>
                      </button>
 
                      <AnimatePresence initial={false}>
                        {isExpanded && (
                          <motion.div
                            initial={{ opacity: 0, height: 0 }}
                            animate={{ opacity: 1, height: "auto" }}
                            exit={{ opacity: 0, height: 0 }}
                            transition={{ duration: 0.3 }}
                            className="space-y-6 overflow-hidden"
                          >
                            <div className="space-y-5 rounded-xl border border-zinc-200 bg-zinc-50 p-6 dark:border-zinc-800 dark:bg-zinc-900">
                              <div>
                                <div className="mb-2 flex items-center gap-2">
                                  <div className="h-1 w-8 rounded-full bg-red-500" />
                                  <div className="text-xs font-bold uppercase tracking-wider text-zinc-900 dark:text-white">
                                    Challenge
                                  </div>
                                </div>
                                <p className="text-sm leading-relaxed text-zinc-700 dark:text-zinc-300">
                                  {study.challenge}
                                </p>
                              </div>
 
                              <div>
                                <div className="mb-2 flex items-center gap-2">
                                  <div className="h-1 w-8 rounded-full bg-blue-500" />
                                  <div className="text-xs font-bold uppercase tracking-wider text-zinc-900 dark:text-white">
                                    Solution
                                  </div>
                                </div>
                                <p className="text-sm leading-relaxed text-zinc-700 dark:text-zinc-300">
                                  {study.solution}
                                </p>
                              </div>
 
                              <div>
                                <div className="mb-2 flex items-center gap-2">
                                  <div className="h-1 w-8 rounded-full bg-green-500" />
                                  <div className="text-xs font-bold uppercase tracking-wider text-zinc-900 dark:text-white">
                                    Results
                                  </div>
                                </div>
                                <p className="text-sm leading-relaxed text-zinc-700 dark:text-zinc-300">
                                  {study.results}
                                </p>
                              </div>
                            </div>
 
                            {study.link && (
                              <a
                                href={study.link}
                                className="group/cta inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-4 py-2.5 text-sm font-semibold text-zinc-900 transition-all hover:border-zinc-300 hover:shadow-md dark:border-zinc-800 dark:bg-zinc-950 dark:text-white dark:hover:border-zinc-700"
                              >
                                View complete case study
                                <ArrowRight className="h-4 w-4 transition-transform group-hover/cta:translate-x-1" />
                              </a>
                            )}
                          </motion.div>
                        )}
                      </AnimatePresence>
                    </div>
                  </div>
                </div>
              </motion.article>
            );
          })}
        </div>
 
        <div className="mt-20 text-center">
          <p className="mb-6 text-lg text-zinc-600 dark:text-zinc-400">
            Want to be our next success story?
          </p>
          <motion.a
            href="#contact"
            className="inline-flex items-center gap-2 rounded-xl bg-zinc-900 px-8 py-4 font-semibold text-white shadow-lg transition-all duration-300 hover:bg-zinc-800 hover:shadow-xl dark:bg-white dark:text-black dark:hover:bg-zinc-100"
            whileHover={{ scale: 1.05 }}
            whileTap={{ scale: 0.95 }}
          >
            <span>Get Started Today</span>
            <ArrowRight className="h-5 w-5" />
          </motion.a>
        </div>
      </div>
    </section>
  );
}

Update the import paths to match your project setup.

Features

  • โœ… Detailed stories - Challenge, Solution, Results format
  • โœ… Key metrics - Visual metric cards with icons
  • โœ… Company info - Name, industry, size, optional logo
  • โœ… Featured badge - Highlight important case studies
  • โœ… Images - Optional hero images
  • โœ… CTA links - Link to full case study pages
  • โœ… Responsive layout - 2-column on desktop, stacked on mobile
  • โœ… Hover effects - Smooth border and shadow animations
  • โœ… Light/dark mode - Full theme support
  • โœ… TypeScript support - Full type safety

Usage

Basic Usage

import CaseStudyShowcase from "@/components/ui/case-study-showcase";
 
const caseStudies = [
  {
    id: "1",
    company: {
      name: "TechFlow Solutions",
      industry: "SaaS",
      size: "50-200 employees",
    },
    title: "How TechFlow increased productivity by 300%",
    description: "Learn how TechFlow transformed their workflow...",
    challenge: "TechFlow was struggling with disconnected tools...",
    solution: "By implementing our platform, TechFlow consolidated...",
    results: "Within 6 months, TechFlow saw a 300% increase...",
    metrics: [
      {label: "Productivity", value: "300%", icon: "trending"},
      {label: "Cost Reduction", value: "40%", icon: "dollar"},
      {label: "Time Saved", value: "20hrs", icon: "users"},
    ],
    image: "/images/case-study-1.jpg",
    link: "/case-studies/techflow",
    featured: true,
  },
];
 
export default function Page() {
  return <CaseStudyShowcase caseStudies={caseStudies} />;
}

Props

CaseStudyShowcaseProps

PropTypeDefaultDescription
caseStudiesCaseStudy[]RequiredArray of case study objects
titlestring"Customer Success Stories"Section title
descriptionstring"See how companies..."Section description
classNamestring""Additional CSS classes

CaseStudy

PropTypeRequiredDescription
idstringYesUnique identifier
companyCompanyYesCompany information
titlestringYesCase study title
descriptionstringYesBrief description
challengestringYesCustomer's challenge
solutionstringYesHow you solved it
resultsstringYesOutcomes achieved
metricsMetric[]YesKey metrics array
imagestringNoHero image URL
linkstringNoLink to full case study
featuredbooleanNoShow featured badge

Use Cases

Perfect for:

  • SaaS landing pages
  • Case study pages
  • Success story sections
  • Social proof displays
  • Sales enablement
  • Marketing materials
  • Investor presentations
  • Customer testimonials

Customization

Add More Icon Types

// In the component, add to iconMap
import {Clock, Target, Zap} from "lucide-react";
 
const iconMap = {
  trending: TrendingUp,
  users: Users,
  dollar: DollarSign,
  clock: Clock,
  target: Target,
  zap: Zap,
};
 
// Update Metric interface
interface Metric {
  label: string;
  value: string;
  icon: "trending" | "users" | "dollar" | "clock" | "target" | "zap";
}

Change Indicator Colors

// Modify the colored bars
<div className="h-1 w-8 rounded-full bg-purple-500" /> // Challenge
<div className="h-1 w-8 rounded-full bg-orange-500" /> // Solution
<div className="h-1 w-8 rounded-full bg-emerald-500" /> // Results

Disable Expand/Collapse

// Remove the button and AnimatePresence
// Show content directly without expansion
<div className="space-y-5 rounded-xl border border-zinc-200 bg-zinc-50 p-6">
  {/* Challenge, Solution, Results content */}
</div>

Change Image Position

// For image on right instead of left
<div className="grid gap-0 lg:grid-cols-5">
  {/* Content first */}
  <div className="flex flex-col p-8 lg:col-span-3 lg:p-12">
    {/* ... content */}
  </div>
 
  {/* Image second */}
  {study.image && (
    <div className="relative h-80 overflow-hidden lg:col-span-2 lg:h-auto">
      {/* ... image */}
    </div>
  )}
</div>

Add Tags

// Add to CaseStudy interface
interface CaseStudy {
  // ... existing props
  tags?: string[];
}
 
// In the component, add after company info
{
  study.tags && (
    <div className="mb-4 flex flex-wrap gap-2">
      {study.tags.map((tag) => (
        <span
          key={tag}
          className="rounded-full bg-zinc-100 px-3 py-1 text-xs font-medium text-zinc-700 dark:bg-zinc-900 dark:text-zinc-300"
        >
          {tag}
        </span>
      ))}
    </div>
  );
}

Add Quote

// Add to CaseStudy interface
interface CaseStudy {
  // ... existing props
  quote?: {
    text: string;
    author: string;
    role: string;
  };
}
 
// In the component, add in expanded content
{
  study.quote && (
    <div className="rounded-xl border-l-4 border-blue-500 bg-blue-50 p-4 dark:bg-blue-950">
      <p className="mb-2 italic text-zinc-700 dark:text-zinc-300">
        "{study.quote.text}"
      </p>
      <div className="text-sm font-semibold text-zinc-900 dark:text-white">
        โ€” {study.quote.author}, {study.quote.role}
      </div>
    </div>
  );
}

Remove Glassmorphism

// For solid metric cards instead of glassmorphic
className =
  "rounded-xl border border-zinc-200 bg-white p-3 text-center dark:border-zinc-800 dark:bg-zinc-900";

Change Grid Ratio

// For 3/5 split (more content space)
<div className="grid gap-0 lg:grid-cols-5">
  {study.image && (
    <div className="... lg:col-span-2"> {/* Image: 2 columns */}
  )}
  <div className="... lg:col-span-3"> {/* Content: 3 columns */}
</div>
 
// For 1/2 split (equal space)
<div className="grid gap-0 lg:grid-cols-2">
  {study.image && (
    <div className="... lg:col-span-1"> {/* Image: 1 column */}
  )}
  <div className="... lg:col-span-1"> {/* Content: 1 column */}
</div>