Finance
Churn Rate Card - Customer Retention
Monitor customer churn rate and retention metrics. Track customer loss and lifetime value impact.
Finance Churn Rate Card
The Finance Churn Rate Card monitors customer retention by tracking churn rate, helping subscription businesses understand and reduce customer attrition.
Preview
Installation
npx shadcn@latest add https://vectormotion.vercel.app/registry/finance-churn-rate-card.jsonFinance Churn Rate Card
'use client'import React from 'react';import { UserMinus } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"import { ResponsiveContainer, RadialBarChart, RadialBar, PolarAngleAxis } from 'recharts';function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs))}interface ChurnData { name: string; value: number; fill: string;}interface ChurnRateCardProps { isInteractive?: boolean; className?: string; title?: string; value?: string; trend?: string; retentionRate?: string; data?: ChurnData[];}const DEFAULT_TITLE = "Churn Rate";const DEFAULT_VALUE = "2.4%";const DEFAULT_TREND = "-0.2% vs last mo";const DEFAULT_RETENTION_RATE = "97.6%";const DEFAULT_DATA: ChurnData[] = [ { name: 'Churn', value: 2.4, fill: '#ef4444' }, // Red for churn];export const ChurnRateCard: React.FC<ChurnRateCardProps> = ({ isInteractive = true, className = "", title = DEFAULT_TITLE, value = DEFAULT_VALUE, trend = DEFAULT_TREND, retentionRate = DEFAULT_RETENTION_RATE, data = DEFAULT_DATA,}) => { const index = 28; 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"> {trend} </span> </div> </div> <div className="rounded-lg bg-emerald-500/10 p-2 text-emerald-500"> <UserMinus className="h-5 w-5" /> </div> </div> <div className="relative z-10 flex-1 min-h-[140px] flex items-center justify-center"> <div className="h-[140px] w-full relative"> <ResponsiveContainer width="100%" height="100%"> <RadialBarChart cx="50%" cy="50%" innerRadius="60%" outerRadius="90%" barSize={12} data={data} startAngle={90} endAngle={-270} > <PolarAngleAxis type="number" domain={[0, 100]} angleAxisId={0} tick={false} /> <RadialBar background={{ fill: '#f4f4f5' }} // zinc-100 dataKey="value" cornerRadius={10} /> </RadialBarChart> </ResponsiveContainer> <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none"> <span className="text-2xl font-bold text-foreground">{value}</span> <span className="text-xs text-muted-foreground">Churn</span> </div> </div> </div> <div className="z-10 mt-2 flex items-center justify-between text-xs pt-2 border-t border-border"> <span className="text-muted-foreground">Retention Rate</span> <span className="font-bold text-foreground">{retentionRate}</span> </div> </motion.div> );};Props
Prop
Type