Finance
Customer Acquisition Cost Card - Marketing ROI
Monitor customer acquisition costs and CAC trends. Track marketing spend efficiency and ROI.
Finance CAC Card
The Finance CAC Card displays Customer Acquisition Cost metrics, breaking down marketing and sales spend to help teams understand the cost of acquiring new customers and optimize their acquisition strategies.
Preview
Installation
npx shadcn@latest add https://vectormotion.vercel.app/registry/finance-cac-card.jsonFinance CAC Card
'use client'import React from 'react';import { Users, TrendingDown } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, BarChart, Bar, Tooltip, XAxis, YAxis } from 'recharts';function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs))}interface CACData { source: string; marketing: number; sales: number;}interface CACCardProps { isInteractive?: boolean; className?: string; title?: string; value?: string; trend?: string; target?: string; data?: CACData[];}const DEFAULT_TITLE = "CAC";const DEFAULT_VALUE = "$345";const DEFAULT_TREND = "-5%";const DEFAULT_TARGET = "$400";const DEFAULT_DATA: CACData[] = [ { source: 'Paid Ads', marketing: 120, sales: 50 }, { source: 'Organic', marketing: 20, sales: 30 }, { source: 'Ref', marketing: 40, sales: 20 },];export const CACCard: React.FC<CACCardProps> = ({ isInteractive = true, className = "", title = DEFAULT_TITLE, value = DEFAULT_VALUE, trend = DEFAULT_TREND, target = DEFAULT_TARGET, data = DEFAULT_DATA,}) => { const index = 27; return ( <motion.div layoutId={isInteractive ? `card-${index}-${title}` : undefined} transition={{ duration: 0.4, ease: "easeOut" }} className={cn( "relative overflow-hidden rounded-xl border border-border bg-card text-card-foreground p-5 shadow-sm transition-all flex flex-col h-full group", isInteractive ? "cursor-pointer hover:border-primary/50 hover:shadow-md" : "", className )} > <div className="mb-2 flex items-start justify-between relative z-10"> <div> <h3 className="font-semibold text-lg text-foreground"> {title} </h3> <div className="flex items-center gap-2 mt-1"> <span className="text-2xl font-bold text-foreground">{value}</span> <span className="text-xs bg-emerald-500/10 text-emerald-600 px-1.5 py-0.5 rounded-full flex items-center gap-0.5"> <TrendingDown className="w-3 h-3" /> {trend} </span> </div> </div> <div className="rounded-lg bg-emerald-500/10 p-2 text-emerald-500"> <Users className="h-5 w-5" /> </div> </div> <div className="relative z-10 flex-1 min-h-[140px]"> <div className="absolute inset-0"> <ResponsiveContainer width="100%" height="100%"> <BarChart layout="vertical" data={data} barGap={2} barSize={16}> <XAxis type="number" hide /> <YAxis dataKey="source" type="category" width={60} tick={{ fontSize: 10, fill: '#71717a' }} axisLine={false} tickLine={false} /> <Tooltip cursor={{ fill: 'transparent' }} contentStyle={{ fontSize: '12px' }} /> <Bar dataKey="marketing" stackId="a" fill="#10b981" radius={[0, 4, 4, 0]} name="Marketing" /> <Bar dataKey="sales" stackId="a" fill="#3b82f6" radius={[0, 4, 4, 0]} name="Sales" /> </BarChart> </ResponsiveContainer> </div> </div> <div className="z-10 mt-2 flex items-center justify-between text-xs pt-2 border-t border-border"> <div className="flex gap-2"> <span className="flex items-center gap-1"><div className="w-2 h-2 rounded-full bg-emerald-500" /> Marketing</span> <span className="flex items-center gap-1"><div className="w-2 h-2 rounded-full bg-blue-500" /> Sales</span> </div> <span className="text-muted-foreground">Target: {target}</span> </div> </motion.div> );};Props
Prop
Type