E-Commerce
Product Categories Card - Category Performance
Monitor product category performance and sales distribution. Track top-performing categories and trends.
Product Categories Card
The Product Categories Card Monitor category performance and sales distribution.
Preview
Installation
ash npx shadcn@latest add https://vectormotion.vercel.app/registry/product-categories-card.json
Product Categories Card
'use client';import React from "react";import { Grid, TrendingUp } 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 Category { name: string; revenue: number; growth: number; color: string; [key: string]: any;}interface ProductCategoriesCardProps { className?: string; title?: string; description?: string; categories?: Category[];}const DEFAULT_TITLE = "Product Categories";const DEFAULT_DESCRIPTION = "Category Performance";const DEFAULT_CATEGORIES: Category[] = [ { name: "Electronics", revenue: 125000, growth: 15, color: "bg-blue-500" }, { name: "Apparel", revenue: 89000, growth: 8, color: "bg-purple-500" }, { name: "Home & Garden", revenue: 67000, growth: 22, color: "bg-emerald-500", }, { name: "Sports", revenue: 45000, growth: -3, color: "bg-orange-500" },];export const ProductCategoriesCard: React.FC<ProductCategoriesCardProps> = ({ className = "", title = DEFAULT_TITLE, description = DEFAULT_DESCRIPTION, categories = DEFAULT_CATEGORIES,}) => { const isInteractive = true; const index = 19; const totalRevenue = categories.reduce((sum, cat) => sum + cat.revenue, 0); 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"> <Grid className="h-5 w-5 text-purple-500" /> </div> </div> <div className="relative z-10 flex-1"> <div className="text-2xl font-bold text-foreground mb-1"> ${(totalRevenue / 1000).toFixed(0)}K </div> <p className="text-sm text-muted-foreground mb-4"> Total category revenue </p> <div className="space-y-3"> {categories.map((category, idx) => { const percentage = Math.round( (category.revenue / totalRevenue) * 100, ); return ( <div key={idx}> <div className="flex justify-between items-center mb-1"> <span className="text-sm text-foreground"> {category.name} </span> <div className="flex items-center gap-2"> <span className={`text-xs font-medium ${category.growth >= 0 ? "text-emerald-500" : "text-red-500" }`} > {category.growth >= 0 ? "+" : ""} {category.growth}% </span> <span className="text-sm font-bold text-foreground"> ${(category.revenue / 1000).toFixed(0)}K </span> </div> </div> <div className="flex items-center gap-2"> <div className="flex-1 bg-zinc-100 dark:bg-zinc-800 rounded-full h-2 overflow-hidden"> <motion.div initial={{ width: 0 }} animate={{ width: `${percentage}%` }} transition={{ duration: 1, delay: idx * 0.1 }} className={`h-full ${category.color} rounded-full`} /> </div> <span className="text-xs text-muted-foreground w-8 text-right"> {percentage}% </span> </div> </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