Components
Data Visualization Card
Data Visualization Card
Interactive bar charts with animated transitions, real-time data updates, and performance metrics.
Revenue Analytics
Last 7 days
+12.5%
45
67
89
56
78
90
65
$12.4k
Total
+8.2%
Growth
1.2k
Users
Installation
1
Install the packages
npm i motion clsx tailwind-merge2
Add util file
lib/util.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3
Copy and paste the following code into your project
data-visualization-card.tsx
"use client";
import { motion } from "motion/react";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
type DataVisualizationCardProps = {
data?: Array<{ label: string; value: number; color: string }>;
height?: number;
};
const DataVisualizationCard = ({
data = [
{ label: "Jan", value: 65, color: "bg-blue-500" },
{ label: "Feb", value: 85, color: "bg-green-500" },
{ label: "Mar", value: 75, color: "bg-purple-500" },
{ label: "Apr", value: 95, color: "bg-orange-500" },
],
height = 200,
}: DataVisualizationCardProps) => {
const [animatedData, setAnimatedData] = useState(data.map(item => ({ ...item, animatedValue: 0 })));
useEffect(() => {
const timer = setTimeout(() => {
setAnimatedData(data.map(item => ({ ...item, animatedValue: item.value })));
}, 500);
return () => clearTimeout(timer);
}, [data]);
const maxValue = Math.max(...data.map(item => item.value));
return (
<div className="w-full max-w-md mx-auto bg-white dark:bg-neutral-900 rounded-lg p-6 shadow-lg">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">Monthly Performance</h3>
<div className="space-y-3" style={{ height }}>
{animatedData.map((item, index) => (
<div key={item.label} className="flex items-center gap-3">
<div className="w-12 text-sm font-medium text-neutral-600 dark:text-neutral-400">
{item.label}
</div>
<div className="flex-1">
<div className="relative h-6 bg-neutral-200 dark:bg-neutral-700 rounded-full overflow-hidden">
<motion.div
className={cn("absolute left-0 top-0 h-full rounded-full", item.color)}
initial={{ width: 0 }}
animate={{ width: `${(item.animatedValue / maxValue) * 100}%` }}
transition={{
duration: 1,
delay: index * 0.2,
ease: "easeOut"
}}
/>
<motion.div
className="absolute right-2 top-1/2 -translate-y-1/2 text-xs font-medium text-white"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: index * 0.2 + 0.5 }}
>
{item.animatedValue}
</motion.div>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default DataVisualizationCard;"use client";
import { motion } from "motion/react";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
type DataVisualizationCardProps = {
data?: Array<{ label: string; value: number; color: string }>;
height?: number;
};
const DataVisualizationCard = ({
data = [
{ label: "Jan", value: 65, color: "bg-blue-500" },
{ label: "Feb", value: 85, color: "bg-green-500" },
{ label: "Mar", value: 75, color: "bg-purple-500" },
{ label: "Apr", value: 95, color: "bg-orange-500" },
],
height = 200,
}: DataVisualizationCardProps) => {
const [animatedData, setAnimatedData] = useState(data.map(item => ({ ...item, animatedValue: 0 })));
useEffect(() => {
const timer = setTimeout(() => {
setAnimatedData(data.map(item => ({ ...item, animatedValue: item.value })));
}, 500);
return () => clearTimeout(timer);
}, [data]);
const maxValue = Math.max(...data.map(item => item.value));
return (
<div className="w-full max-w-md mx-auto bg-white dark:bg-neutral-900 rounded-lg p-6 shadow-lg">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">Monthly Performance</h3>
<div className="space-y-3" style={{ height }}>
{animatedData.map((item, index) => (
<div key={item.label} className="flex items-center gap-3">
<div className="w-12 text-sm font-medium text-neutral-600 dark:text-neutral-400">
{item.label}
</div>
<div className="flex-1">
<div className="relative h-6 bg-neutral-200 dark:bg-neutral-700 rounded-full overflow-hidden">
<motion.div
className={cn("absolute left-0 top-0 h-full rounded-full", item.color)}
initial={{ width: 0 }}
animate={{ width: `${(item.animatedValue / maxValue) * 100}%` }}
transition={{
duration: 1,
delay: index * 0.2,
ease: "easeOut"
}}
/>
<motion.div
className="absolute right-2 top-1/2 -translate-y-1/2 text-xs font-medium text-white"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: index * 0.2 + 0.5 }}
>
{item.animatedValue}
</motion.div>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default DataVisualizationCard;4
Update the import paths to match your project setup
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data | array | [] | Array of data points for the chart. |
| height | number | 200 | Height of the chart in pixels. |