Financial performance chart with two series: an amber area chart with SVG vertical-stripe fill and a dashed emerald line. Features a period toggle (1D, 5D, 1M, 6M, 1Y), download button, metric labels with colored dots, large value display, horizontal grid lines, custom Y-axis (0M–3M), and a custom tooltip. Built with recharts ComposedChart. Perfect for fintech dashboards, portfolio trackers, and analytics platforms.
Files
"use client"
import { useState } from "react"
import { Download } from "lucide-react"
import {
Area,
CartesianGrid,
ComposedChart,
Line,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
import { cn } from "@/lib/utils"
const PERIODS = ["1D", "5D", "1M", "6M", "1Y"] as const
type Period = (typeof PERIODS)[number]
const data = [
{ month: "Jan", usdc: 2050000, token: 2200000 },
{ month: "Feb", usdc: 1520000, token: 2050000 },
{ month: "Mar", usdc: 1700000, token: 2100000 },
{ month: "Apr", usdc: 1480000, token: 1950000 },
{ month: "May", usdc: 1850000, token: 2000000 },
{ month: "Jun", usdc: 2150000, token: 2100000 },
{ month: "Jul", usdc: 2500000, token: 2000000 },
{ month: "Aug", usdc: 2950000, token: 1980000 },
{ month: "Sep", usdc: 2200000, token: 1760000 },
{ month: "Oct", usdc: 2560000, token: 1590000 },
{ month: "Nov", usdc: 2830000, token: 1710000 },
{ month: "Dec", usdc: 3180000, token: 1960000 },
]
const metrics = {
usdc: { label: "USDC", value: "32,658.45", color: "#f59e0b" },
token: { label: "Token price", value: "1.028", color: "#10b981" },
}
function formatYAxis(value: number) {
if (value === 0) return "0M"
return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}M`
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function ChartTooltip({ active, payload, label }: any) {
if (active && payload && payload.length) {
return (
<div className="bg-background border-border rounded-lg border px-3 py-2 shadow-md">
<p className="text-muted-foreground mb-2 text-xs font-light">{label}</p>
{payload.map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(entry: any) => (
<div key={entry.name} className="flex items-center gap-2 text-sm">
<div
className="h-2 w-2 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span className="text-foreground font-light">
{formatYAxis(entry.value)}
</span>
</div>
)
)}
</div>
)
}
return null
}
export default function RecentPerformanceChart() {
const [activePeriod, setActivePeriod] = useState<Period>("1M")
return (
<div className="bg-card border-border w-full max-w-4xl rounded-2xl border p-6 shadow-sm">
{/* Header */}
<div className="mb-5 flex items-center justify-between">
<h2 className="text-foreground text-lg font-semibold">
Recent performance
</h2>
<div className="flex items-center gap-0.5">
{PERIODS.map((p) => (
<button
key={p}
onClick={() => setActivePeriod(p)}
className={cn(
"rounded-md px-3 py-1 text-sm transition-colors",
activePeriod === p
? "text-foreground font-light"
: "text-muted-foreground hover:text-foreground font-light"
)}
>
{p}
</button>
))}
<button className="text-muted-foreground hover:text-foreground ml-2 rounded-md p-1.5 transition-colors">
<Download className="h-4 w-4" />
</button>
</div>
</div>
{/* Metrics */}
<div className="mb-6 flex items-start gap-10">
{Object.values(metrics).map((m) => (
<div key={m.label}>
<div className="mb-1 flex items-center gap-2">
<div
className="h-2.5 w-2.5 rounded-full"
style={{ backgroundColor: m.color }}
/>
<span className="text-muted-foreground text-sm">{m.label}</span>
</div>
<p className="text-foreground text-3xl font-light tracking-tight">
{m.value}
</p>
</div>
))}
</div>
{/* Chart */}
<div className="h-72">
<ResponsiveContainer width="100%" height="100%">
<ComposedChart
data={data}
margin={{ top: 10, right: 4, bottom: 0, left: 0 }}
>
<defs>
<pattern
id="usdcStripes"
x="0"
y="0"
width="5"
height="8"
patternUnits="userSpaceOnUse"
>
<line
x1="0"
y1="0"
x2="0"
y2="8"
stroke="#f59e0b"
strokeWidth="2.5"
strokeOpacity="0.45"
/>
</pattern>
</defs>
<CartesianGrid
vertical={false}
stroke="var(--border)"
strokeOpacity={0.8}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{
fontSize: 12,
style: { fill: "var(--muted-foreground))" },
}}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{
fontSize: 12,
style: { fill: "var(--muted-foreground)" },
}}
tickFormatter={formatYAxis}
domain={[0, 3500000]}
ticks={[0, 1000000, 1500000, 2000000, 2500000, 3000000]}
width={36}
/>
<Tooltip
content={<ChartTooltip />}
cursor={{ stroke: "#f59e0b", strokeWidth: 1.5 }}
/>
<Area
type="monotone"
dataKey="usdc"
stroke="#f59e0b"
strokeWidth={2}
fill="url(#usdcStripes)"
dot={false}
activeDot={{ r: 5, fill: "#f59e0b", strokeWidth: 0 }}
/>
<Line
type="monotone"
dataKey="token"
stroke="#10b981"
strokeWidth={1.5}
strokeDasharray="5 4"
dot={false}
activeDot={{ r: 4, fill: "#10b981", strokeWidth: 0 }}
/>
</ComposedChart>
</ResponsiveContainer>
</div>
</div>
)
}
Dual-series performance chart with striped area, dashed line, and period toggle
recent-performance-chart-01
Recent performance
USDC
32,658.45
Token price
1.028
"use client"
import { useState } from "react"
import { Download } from "lucide-react"
import {
Area,
CartesianGrid,
ComposedChart,
Line,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
import { cn } from "@/lib/utils"
const PERIODS = ["1D", "5D", "1M", "6M", "1Y"] as const
type Period = (typeof PERIODS)[number]
const data = [
{ month: "Jan", usdc: 2050000, token: 2200000 },
{ month: "Feb", usdc: 1520000, token: 2050000 },
{ month: "Mar", usdc: 1700000, token: 2100000 },
{ month: "Apr", usdc: 1480000, token: 1950000 },
{ month: "May", usdc: 1850000, token: 2000000 },
{ month: "Jun", usdc: 2150000, token: 2100000 },
{ month: "Jul", usdc: 2500000, token: 2000000 },
{ month: "Aug", usdc: 2950000, token: 1980000 },
{ month: "Sep", usdc: 2200000, token: 1760000 },
{ month: "Oct", usdc: 2560000, token: 1590000 },
{ month: "Nov", usdc: 2830000, token: 1710000 },
{ month: "Dec", usdc: 3180000, token: 1960000 },
]
const metrics = {
usdc: { label: "USDC", value: "32,658.45", color: "#f59e0b" },
token: { label: "Token price", value: "1.028", color: "#10b981" },
}
function formatYAxis(value: number) {
if (value === 0) return "0M"
return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}M`
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function ChartTooltip({ active, payload, label }: any) {
if (active && payload && payload.length) {
return (
<div className="bg-background border-border rounded-lg border px-3 py-2 shadow-md">
<p className="text-muted-foreground mb-2 text-xs font-light">{label}</p>
{payload.map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(entry: any) => (
<div key={entry.name} className="flex items-center gap-2 text-sm">
<div
className="h-2 w-2 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span className="text-foreground font-light">
{formatYAxis(entry.value)}
</span>
</div>
)
)}
</div>
)
}
return null
}
export default function RecentPerformanceChart() {
const [activePeriod, setActivePeriod] = useState<Period>("1M")
return (
<div className="bg-card border-border w-full max-w-4xl rounded-2xl border p-6 shadow-sm">
{/* Header */}
<div className="mb-5 flex items-center justify-between">
<h2 className="text-foreground text-lg font-semibold">
Recent performance
</h2>
<div className="flex items-center gap-0.5">
{PERIODS.map((p) => (
<button
key={p}
onClick={() => setActivePeriod(p)}
className={cn(
"rounded-md px-3 py-1 text-sm transition-colors",
activePeriod === p
? "text-foreground font-light"
: "text-muted-foreground hover:text-foreground font-light"
)}
>
{p}
</button>
))}
<button className="text-muted-foreground hover:text-foreground ml-2 rounded-md p-1.5 transition-colors">
<Download className="h-4 w-4" />
</button>
</div>
</div>
{/* Metrics */}
<div className="mb-6 flex items-start gap-10">
{Object.values(metrics).map((m) => (
<div key={m.label}>
<div className="mb-1 flex items-center gap-2">
<div
className="h-2.5 w-2.5 rounded-full"
style={{ backgroundColor: m.color }}
/>
<span className="text-muted-foreground text-sm">{m.label}</span>
</div>
<p className="text-foreground text-3xl font-light tracking-tight">
{m.value}
</p>
</div>
))}
</div>
{/* Chart */}
<div className="h-72">
<ResponsiveContainer width="100%" height="100%">
<ComposedChart
data={data}
margin={{ top: 10, right: 4, bottom: 0, left: 0 }}
>
<defs>
<pattern
id="usdcStripes"
x="0"
y="0"
width="5"
height="8"
patternUnits="userSpaceOnUse"
>
<line
x1="0"
y1="0"
x2="0"
y2="8"
stroke="#f59e0b"
strokeWidth="2.5"
strokeOpacity="0.45"
/>
</pattern>
</defs>
<CartesianGrid
vertical={false}
stroke="var(--border)"
strokeOpacity={0.8}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{
fontSize: 12,
style: { fill: "var(--muted-foreground))" },
}}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{
fontSize: 12,
style: { fill: "var(--muted-foreground)" },
}}
tickFormatter={formatYAxis}
domain={[0, 3500000]}
ticks={[0, 1000000, 1500000, 2000000, 2500000, 3000000]}
width={36}
/>
<Tooltip
content={<ChartTooltip />}
cursor={{ stroke: "#f59e0b", strokeWidth: 1.5 }}
/>
<Area
type="monotone"
dataKey="usdc"
stroke="#f59e0b"
strokeWidth={2}
fill="url(#usdcStripes)"
dot={false}
activeDot={{ r: 5, fill: "#f59e0b", strokeWidth: 0 }}
/>
<Line
type="monotone"
dataKey="token"
stroke="#10b981"
strokeWidth={1.5}
strokeDasharray="5 4"
dot={false}
activeDot={{ r: 4, fill: "#10b981", strokeWidth: 0 }}
/>
</ComposedChart>
</ResponsiveContainer>
</div>
</div>
)
}