Vector Motion
Finance

Monthly Recurring Revenue Card - Subscription Metrics

Monitor monthly recurring revenue and subscription growth. Track MRR trends and revenue stability.

Finance MRR Card

The Finance MRR Card presents Monthly Recurring Revenue growth trends with a bar chart visualization, helping SaaS and subscription businesses monitor their recurring revenue performance over time.

Preview

Installation

npx shadcn@latest add https://vectormotion.vercel.app/registry/finance-mrr-card.json
Finance MRR Card
'use client'import React from 'react';import { BarChart3, TrendingUp } from 'lucide-react';import { ResponsiveContainer, AreaChart, Area, Tooltip, XAxis } from 'recharts';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"function cn(...inputs: ClassValue[]) {  return twMerge(clsx(inputs))}interface MRRData {  month: string;  val: number;  [key: string]: any;}interface MRRCardProps {  isInteractive?: boolean;  className?: string;  title?: string;  amount?: string;  growth?: string;  data?: MRRData[];}const DEFAULT_TITLE = "MRR Growth";const DEFAULT_AMOUNT = "$71.2k";const DEFAULT_GROWTH = "+12.8%";const DEFAULT_DATA: MRRData[] = [  { month: 'Jun', val: 45 },  { month: 'Jul', val: 48 },  { month: 'Aug', val: 52 },  { month: 'Sep', val: 58 },  { month: 'Oct', val: 63 },  { month: 'Nov', val: 71 },];export const MRRCard: React.FC<MRRCardProps> = ({  isInteractive = true,  className = "",  title = DEFAULT_TITLE,  amount = DEFAULT_AMOUNT,  growth = DEFAULT_GROWTH,  data = DEFAULT_DATA,}) => {  const index = 26;  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">{amount}</span>            <span className="text-xs font-medium text-emerald-600 bg-emerald-500/10 px-1.5 py-0.5 rounded-full flex items-center gap-0.5">              <TrendingUp className="w-3 h-3" /> {growth}            </span>          </div>        </div>        <div className="rounded-lg bg-emerald-500/10 p-2 text-emerald-500">          <BarChart3 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%">            <AreaChart data={data}>              <defs>                <linearGradient id="colorMRR" x1="0" y1="0" x2="0" y2="1">                  <stop offset="5%" stopColor="#10b981" stopOpacity={0.3} />                  <stop offset="95%" stopColor="#10b981" stopOpacity={0} />                </linearGradient>              </defs>              <Tooltip                cursor={{ stroke: '#10b981', strokeWidth: 1, strokeDasharray: '3 3' }}                contentStyle={{ backgroundColor: 'var(--tooltip-bg)', borderRadius: '8px', border: 'none', color: 'var(--tooltip-text)' }}                formatter={(val) => [`$${val}k`, 'MRR']}              />              <XAxis dataKey="month" axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#71717a' }} />              <Area                type="monotone"                dataKey="val"                stroke="#10b981"                fill="url(#colorMRR)"                strokeWidth={2}                animationDuration={1500}              />            </AreaChart>          </ResponsiveContainer>        </div>      </div>    </motion.div>  );};

Props

Prop

Type