- Gallery
- Dashboard & Analytics
- RevenueChart
New
RevenueChart
CSS-only area chart with gradient fill, axis labels, and hover interaction
Dashboard & Analyticschartrevenuearea-chartanalytics
Dependencies
shadcn/ui components needed:
npx shadcn@latest add cardHow to use this component
Copy the code below into your project. Make sure you have the required shadcn/ui dependencies installed. Then import and use the component in your pages or layouts.
Code
1"use client"23import * as React from "react"4import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"5import { cn } from "@/lib/utils"67interface RevenueChartProps {8 data?: { label: string; value: number }[]9 className?: string10}1112export function RevenueChart({ data = [13 { label: "Jan", value: 12000 },14 { label: "Feb", value: 19000 },15 { label: "Mar", value: 15000 },16 { label: "Apr", value: 22000 },17 { label: "May", value: 28000 },18 { label: "Jun", value: 24000 },19], className }: RevenueChartProps) {20 const total = data.reduce((sum, d) => sum + d.value, 0)21 const max = Math.max(...data.map(d => d.value))22 const width = 60023 const height = 20024 const padding = 4025 26 const points = data.map((d, i) => {27 const x = padding + (i / (data.length - 1)) * (width - padding * 2)28 const y = height - padding - (d.value / max) * (height - padding * 2)29 return `${x},${y}`30 }).join(" ")31 32 const areaPoints = `${padding},${height - padding} ${points} ${width - padding},${height - padding}`3334 return (35 <Card className={cn("w-full", className)}>36 <CardHeader className="pb-4">37 <CardTitle>Revenue</CardTitle>38 <p className="text-2xl font-bold text-primary">${total.toLocaleString()}</p>39 </CardHeader>40 <CardContent>41 <div className="relative w-full overflow-hidden">42 <svg viewBox={`0 0 ${width} ${height}`} className="w-full h-auto">43 <defs>44 <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">45 <stop offset="0%" stopColor="rgb(59 130 246)" stopOpacity="0.4" />46 <stop offset="100%" stopColor="rgb(59 130 246)" stopOpacity="0" />47 </linearGradient>48 </defs>49 <polygon points={areaPoints} fill="url(#gradient)" />50 <polyline points={points} fill="none" stroke="rgb(59 130 246)" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />51 {data.map((d, i) => {52 const x = padding + (i / (data.length - 1)) * (width - padding * 2)53 const y = height - padding - (d.value / max) * (height - padding * 2)54 return (55 <g key={i} className="group">56 <circle cx={x} cy={y} r="6" fill="white" stroke="rgb(59 130 246)" strokeWidth="3" className="group-hover:r-8 transition-all duration-200" />57 <text x={x} y={height - 10} textAnchor="middle" className="text-xs fill-muted-foreground">{d.label}</text>58 </g>59 )60 })}61 {[0, 0.5, 1].map((p, i) => (62 <g key={i}>63 <line x1={padding - 10} y1={height - padding - p * (height - padding * 2)} x2={width - padding} y2={height - padding - p * (height - padding * 2)} stroke="rgb(226 232 240)" strokeDasharray="4" />64 <text x={padding - 15} y={height - padding - p * (height - padding * 2) + 4} textAnchor="end" className="text-xs fill-muted-foreground">${(max * p / 1000).toFixed(0)}k</text>65 </g>66 ))}67 </svg>68 </div>69 </CardContent>70 </Card>71 )72}