Success Stories
Customer Success Stories
See how companies are achieving their goals with our platform
Featured
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.
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.
$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.
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 TodayInstallation
Install dependencies
npm install framer-motion lucide-reactCopy 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
| Prop | Type | Default | Description |
|---|---|---|---|
caseStudies | CaseStudy[] | Required | Array of case study objects |
title | string | "Customer Success Stories" | Section title |
description | string | "See how companies..." | Section description |
className | string | "" | Additional CSS classes |
CaseStudy
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier |
company | Company | Yes | Company information |
title | string | Yes | Case study title |
description | string | Yes | Brief description |
challenge | string | Yes | Customer's challenge |
solution | string | Yes | How you solved it |
results | string | Yes | Outcomes achieved |
metrics | Metric[] | Yes | Key metrics array |
image | string | No | Hero image URL |
link | string | No | Link to full case study |
featured | boolean | No | Show 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" /> // ResultsDisable 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>