Vector Motion
E-Commerce

Sales Funnel Card - Conversion Tracking

Visualize complete sales funnel from awareness to conversion. Track funnel drop-off and optimize each stage.

Sales Funnel Card

The Sales Funnel Card Visualize conversion funnel from visitors to purchases.

Preview

Installation

ash npx shadcn@latest add https://vectormotion.vercel.app/registry/sales-funnel-card.json

Sales Funnel Card
'use client';import React from "react";import { Filter, Users } from "lucide-react";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 FunnelStage {  stage: string;  count: number;  percentage: number;  color: string;  [key: string]: any;}interface SalesFunnelCardProps {  className?: string;  title?: string;  description?: string;  overallConversion?: string;  funnelStages?: FunnelStage[];}const DEFAULT_TITLE = "Sales Funnel";const DEFAULT_DESCRIPTION = "Conversion Flow";const DEFAULT_OVERALL_CONVERSION = "6.0%";const DEFAULT_FUNNEL_STAGES: FunnelStage[] = [  { stage: "Visitors", count: 10000, percentage: 100, color: "bg-blue-500" },  {    stage: "Product Views",    count: 5000,    percentage: 50,    color: "bg-purple-500",  },  {    stage: "Add to Cart",    count: 2000,    percentage: 20,    color: "bg-indigo-500",  },  { stage: "Checkout", count: 800, percentage: 8, color: "bg-violet-500" },  { stage: "Purchase", count: 600, percentage: 6, color: "bg-emerald-500" },];export const SalesFunnelCard: React.FC<SalesFunnelCardProps> = ({  className = "",  title = DEFAULT_TITLE,  description = DEFAULT_DESCRIPTION,  overallConversion = DEFAULT_OVERALL_CONVERSION,  funnelStages = DEFAULT_FUNNEL_STAGES,}) => {  const isInteractive = true;  const index = 4;  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-6 shadow-sm transition-all flex flex-col group",        isInteractive          ? "cursor-pointer hover:border-zinc-300 dark:hover:border-zinc-700"          : "",        className,      )}    >      <div className="mb-4 flex items-start justify-between relative z-10">        <div>          <h3 className="font-semibold text-lg tracking-tight text-foreground">            {title}          </h3>          {description && (            <p className="text-sm text-muted-foreground mt-1">{description}</p>          )}        </div>        <div className="rounded-full bg-zinc-100 dark:bg-zinc-800 p-2 text-foreground flex items-center justify-center">          <Filter className="h-5 w-5 text-indigo-500" />        </div>      </div>      <div className="relative z-10 flex-1">        <div className="space-y-2">          {funnelStages.map((stage, idx) => (            <div key={idx}>              <div className="flex justify-between items-center mb-1">                <span className="text-sm font-medium text-foreground">                  {stage.stage}                </span>                <div className="flex items-center gap-2">                  <span className="text-sm font-bold text-foreground">                    {stage.count.toLocaleString()}                  </span>                  <span className="text-xs text-muted-foreground">                    ({stage.percentage}%)                  </span>                </div>              </div>              <motion.div                initial={{ width: 0 }}                animate={{ width: `${stage.percentage}%` }}                transition={{ duration: 0.8, delay: idx * 0.1 }}                className={`h-8 ${stage.color} rounded-lg flex items-center justify-center`}                style={{ minWidth: "60px" }}              >                {idx < funnelStages.length - 1 && (                  <span className="text-xs text-white font-medium">                    {(                      (funnelStages[idx + 1].count / stage.count) *                      100                    ).toFixed(1)}                    % →                  </span>                )}              </motion.div>            </div>          ))}        </div>        <div className="mt-4 pt-4 border-t border-border">          <div className="flex justify-between items-center">            <span className="text-sm text-muted-foreground">              Overall Conversion            </span>            <span className="text-lg font-bold text-emerald-500">              {overallConversion}            </span>          </div>        </div>      </div>    </motion.div>  );};

Usage

This component is a data-rich dashboard card displaying e-commerce metrics with animated visualizations and dark mode support. Perfect for dashboards, landing pages, and analytics interfaces.

Prop

Type