
Narrow card with a radial ring showing progress toward a weekly listening goal, minutes in the center, the remaining track visible and a footer note. Client component on recharts 3.8.
blocks/charts/radial-chart-01/index.tsx
"use client"
import {
Label,
PolarAngleAxis,
PolarRadiusAxis,
RadialBar,
RadialBarChart,
} from "recharts"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { ChartContainer, type ChartConfig } from "@/components/ui/chart"
// The copy: change text here, not in the markup.
const COPY = {
title: "Weekly goal",
description: "October 12 to 18",
unit: "of 600 minutes",
note: "138 minutes to go, about 20 a day.",
} as const
const GOAL = 600
const LISTENED = [{ goal: "week", minutes: 462, fill: "var(--color-minutes)" }]
const CHART_CONFIG = {
minutes: { label: "Minutes", color: "var(--chart-2)" },
} satisfies ChartConfig
export default function RadialChart01() {
return (
<Card className="mx-auto w-full max-w-xs">
<CardHeader>
<CardTitle>
<h2>{COPY.title}</h2>
</CardTitle>
<CardDescription>{COPY.description}</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer
config={CHART_CONFIG}
className="mx-auto aspect-square max-h-64"
>
<RadialBarChart
data={LISTENED}
startAngle={90}
endAngle={-270}
innerRadius={86}
outerRadius={112}
>
{/* The goal sets the full turn; the track shows what is left. */}
<PolarAngleAxis type="number" domain={[0, GOAL]} tick={false} />
<RadialBar dataKey="minutes" background cornerRadius={12} />
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
<Label
content={({ viewBox }) => {
if (!viewBox || !("cx" in viewBox)) return null
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-medium tabular-nums"
>
{LISTENED[0].minutes}
</tspan>
<tspan
x={viewBox.cx}
y={(viewBox.cy ?? 0) + 28}
className="fill-muted-foreground"
>
{COPY.unit}
</tspan>
</text>
)
}}
/>
</PolarRadiusAxis>
</RadialBarChart>
</ChartContainer>
</CardContent>
<CardFooter className="justify-center text-sm text-muted-foreground">
<p>{COPY.note}</p>
</CardFooter>
</Card>
)
}