Chartstandard
recharts 위에 색 설정과 툴팁·범례 모양을 얹은 차트 틀(chart)입니다. shadcn base-nova 의 원본을 그대로 담은 아이템입니다. 차트 종류(막대, 선 등)는 recharts 를 그대로 씁니다.
설치
pnpm
pnpm dlx shadcn@4.23.0 add @uikit/chart의존 아이템card
Default
chart-example.tsx
"use client"
import * as React from "react"import { Area, AreaChart, Bar, BarChart, CartesianGrid, Label, Line, LineChart, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart, RadialBar, RadialBarChart, XAxis,} from "recharts"
import { Example, ExampleWrapper,} from "@/components/example"import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@/components/ui/card"import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig,} from "@/components/ui/chart"import { TrendingUpIcon } from "lucide-react"
const areaChartData = [ { month: "January", desktop: 186 }, { month: "February", desktop: 305 }, { month: "March", desktop: 237 }, { month: "April", desktop: 73 }, { month: "May", desktop: 209 }, { month: "June", desktop: 214 },]
const areaChartConfig = { desktop: { label: "Desktop", color: "var(--chart-1)", },} satisfies ChartConfig
export default function ChartExample() { return ( <ExampleWrapper> <ChartAreaExample /> <ChartBarExample /> <ChartLineExample /> <ChartPieExample /> <ChartRadialExample /> <ChartRadarExample /> </ExampleWrapper> )}
function ChartAreaExample() { return ( <Example title="Area Chart"> <Card className="w-full"> <CardHeader> <CardTitle>Area Chart</CardTitle> <CardDescription> Showing total visitors for the last 6 months </CardDescription> </CardHeader> <CardContent> <ChartContainer config={areaChartConfig}> <AreaChart accessibilityLayer data={areaChartData} margin={{ left: 12, right: 12, }} > <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} /> <Area dataKey="desktop" type="natural" fill="var(--color-desktop)" fillOpacity={0.4} stroke="var(--color-desktop)" /> </AreaChart> </ChartContainer> </CardContent> <CardFooter> <div className="flex w-full items-start gap-2"> <div className="grid gap-2"> <div className="flex items-center gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="flex items-center gap-2 leading-none text-muted-foreground"> January - June 2024 </div> </div> </div> </CardFooter> </Card> </Example> )}
const barChartData = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 },]
const barChartConfig = { desktop: { label: "Desktop", color: "var(--chart-1)", }, mobile: { label: "Mobile", color: "var(--chart-2)", },} satisfies ChartConfig
function ChartBarExample() { return ( <Example title="Bar Chart"> <Card className="w-full"> <CardHeader> <CardTitle>Bar Chart - Multiple</CardTitle> <CardDescription>January - June 2024</CardDescription> </CardHeader> <CardContent> <ChartContainer config={barChartConfig}> <BarChart accessibilityLayer data={barChartData}> <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} tickMargin={10} axisLine={false} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="dashed" />} /> <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} /> <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} /> </BarChart> </ChartContainer> </CardContent> <CardFooter className="flex-col items-start gap-2"> <div className="flex gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="leading-none text-muted-foreground"> Showing total visitors for the last 6 months </div> </CardFooter> </Card> </Example> )}
const lineChartData = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 },]
const lineChartConfig = { desktop: { label: "Desktop", color: "var(--chart-1)", }, mobile: { label: "Mobile", color: "var(--chart-2)", },} satisfies ChartConfig
function ChartLineExample() { return ( <Example title="Line Chart"> <Card className="w-full"> <CardHeader> <CardTitle>Line Chart - Multiple</CardTitle> <CardDescription>January - June 2024</CardDescription> </CardHeader> <CardContent> <ChartContainer config={lineChartConfig}> <LineChart accessibilityLayer data={lineChartData} margin={{ left: 12, right: 12, }} > <CartesianGrid vertical={false} /> <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} tickFormatter={(value) => value.slice(0, 3)} /> <ChartTooltip cursor={false} content={<ChartTooltipContent />} /> <Line dataKey="desktop" type="monotone" stroke="var(--color-desktop)" strokeWidth={2} dot={false} /> <Line dataKey="mobile" type="monotone" stroke="var(--color-mobile)" strokeWidth={2} dot={false} /> </LineChart> </ChartContainer> </CardContent> <CardFooter> <div className="flex w-full items-start gap-2"> <div className="grid gap-2"> <div className="flex items-center gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="flex items-center gap-2 leading-none text-muted-foreground"> Showing total visitors for the last 6 months </div> </div> </div> </CardFooter> </Card> </Example> )}
const pieChartData = [ { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" }, { browser: "safari", visitors: 200, fill: "var(--color-safari)" }, { browser: "firefox", visitors: 287, fill: "var(--color-firefox)" }, { browser: "edge", visitors: 173, fill: "var(--color-edge)" }, { browser: "other", visitors: 190, fill: "var(--color-other)" },]
const pieChartConfig = { visitors: { label: "Visitors", }, chrome: { label: "Chrome", color: "var(--chart-1)", }, safari: { label: "Safari", color: "var(--chart-2)", }, firefox: { label: "Firefox", color: "var(--chart-3)", }, edge: { label: "Edge", color: "var(--chart-4)", }, other: { label: "Other", color: "var(--chart-5)", },} satisfies ChartConfig
function ChartPieExample() { const totalVisitors = React.useMemo(() => { return pieChartData.reduce((acc, curr) => acc + curr.visitors, 0) }, [])
return ( <Example title="Pie Chart"> <Card className="w-full"> <CardHeader className="items-center pb-0"> <CardTitle>Pie Chart - Donut with Text</CardTitle> <CardDescription>January - June 2024</CardDescription> </CardHeader> <CardContent className="flex-1 pb-0"> <ChartContainer config={pieChartConfig} className="mx-auto aspect-square max-h-[250px]" > <PieChart> <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} /> <Pie data={pieChartData} dataKey="visitors" nameKey="browser" innerRadius={60} strokeWidth={5} > <Label content={({ viewBox }) => { if (viewBox && "cx" in viewBox && "cy" in viewBox) { return ( <text x={viewBox.cx} y={viewBox.cy} textAnchor="middle" dominantBaseline="middle" > <tspan x={viewBox.cx} y={viewBox.cy} className="fill-foreground text-3xl font-bold" > {totalVisitors.toLocaleString()} </tspan> <tspan x={viewBox.cx} y={(viewBox.cy || 0) + 24} className="fill-muted-foreground" > Visitors </tspan> </text> ) } }} /> </Pie> </PieChart> </ChartContainer> </CardContent> <CardFooter className="flex-col gap-2"> <div className="flex items-center gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="leading-none text-muted-foreground"> Showing total visitors for the last 6 months </div> </CardFooter> </Card> </Example> )}
const radarChartData = [ { month: "January", desktop: 186, mobile: 80 }, { month: "February", desktop: 305, mobile: 200 }, { month: "March", desktop: 237, mobile: 120 }, { month: "April", desktop: 73, mobile: 190 }, { month: "May", desktop: 209, mobile: 130 }, { month: "June", desktop: 214, mobile: 140 },]
const radarChartConfig = { desktop: { label: "Desktop", color: "var(--chart-1)", }, mobile: { label: "Mobile", color: "var(--chart-2)", },} satisfies ChartConfig
function ChartRadarExample() { return ( <Example title="Radar Chart"> <Card className="w-full"> <CardHeader className="items-center pb-4"> <CardTitle>Radar Chart - Multiple</CardTitle> <CardDescription> Showing total visitors for the last 6 months </CardDescription> </CardHeader> <CardContent className="pb-0"> <ChartContainer config={radarChartConfig} className="mx-auto aspect-square max-h-[250px]" > <RadarChart data={radarChartData}> <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" />} /> <PolarAngleAxis dataKey="month" /> <PolarGrid /> <Radar dataKey="desktop" fill="var(--color-desktop)" fillOpacity={0.6} /> <Radar dataKey="mobile" fill="var(--color-mobile)" /> </RadarChart> </ChartContainer> </CardContent> <CardFooter className="flex-col gap-2"> <div className="flex items-center gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="flex items-center gap-2 leading-none text-muted-foreground"> January - June 2024 </div> </CardFooter> </Card> </Example> )}
const radialChartData = [ { browser: "safari", visitors: 1260, fill: "var(--color-safari)" },]
const radialChartConfig = { visitors: { label: "Visitors", }, safari: { label: "Safari", color: "var(--chart-2)", },} satisfies ChartConfig
function ChartRadialExample() { return ( <Example title="Radial Chart"> <Card className="w-full"> <CardHeader> <CardTitle>Radial Chart - Shape</CardTitle> <CardDescription>January - June 2024</CardDescription> </CardHeader> <CardContent className="flex-1 pb-0"> <ChartContainer config={radialChartConfig} className="mx-auto aspect-square max-h-[210px]" > <RadialBarChart data={radialChartData} endAngle={100} innerRadius={64} outerRadius={94} > <PolarGrid gridType="circle" radialLines={false} stroke="none" className="first:fill-muted last:fill-background" polarRadius={[86, 74]} /> <RadialBar dataKey="visitors" background /> <PolarRadiusAxis tick={false} tickLine={false} axisLine={false}> <Label content={({ viewBox }) => { if (viewBox && "cx" in viewBox && "cy" in viewBox) { return ( <text x={viewBox.cx} y={viewBox.cy} textAnchor="middle" dominantBaseline="middle" > <tspan x={viewBox.cx} y={viewBox.cy} className="fill-foreground text-4xl font-bold" > {radialChartData[0]?.visitors.toLocaleString()} </tspan> <tspan x={viewBox.cx} y={(viewBox.cy || 0) + 24} className="fill-muted-foreground" > Visitors </tspan> </text> ) } }} /> </PolarRadiusAxis> </RadialBarChart> </ChartContainer> </CardContent> <CardFooter className="flex-col gap-2"> <div className="flex items-center gap-2 leading-none font-medium"> Trending up by 5.2% this month{" "} <TrendingUpIcon className="size-4" /> </div> <div className="leading-none text-muted-foreground"> Showing total visitors for the last 6 months </div> </CardFooter> </Card> </Example> )}