Component

Donut Chart

Donut pie chart with five segments and a centred total-visitors label. Uses chart-* color tokens so it adapts to any active theme.

Usage

Use donut charts to show part-to-whole relationships when you want to highlight a single summary value in the centre. Keep to 3–6 segments for readability.

Playground

Preview
Donut Chart
January – June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months

Configure

Code

const chartData = [
  { 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 chartConfig = {
  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

const totalVisitors = chartData.reduce((acc, curr) => acc + curr.visitors, 0)

<Card className="flex flex-col">
  <CardHeader className="items-center pb-0">
    <CardTitle>Donut Chart</CardTitle>
    <CardDescription>January  June 2024</CardDescription>
  </CardHeader>
  <CardContent className="flex-1 pb-0">
    <ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
      <PieChart>
        <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
        <Pie
          data={chartData}
          dataKey="visitors"
          nameKey="browser"
          innerRadius={60}
          strokeWidth={5}
          stroke="var(--card)"
        >
          <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 text-sm">
    <div className="flex items-center gap-2 leading-none font-medium">
      Trending up by 5.2% this month <TrendUp className="size-4" />
    </div>
    <div className="leading-none text-muted-foreground">
      Showing total visitors for the last 6 months
    </div>
  </CardFooter>
</Card>

Do

  • Limit segments to 3–6, more slices become difficult to distinguish
  • Use chart-* color tokens so segments adapt automatically when the theme changes
  • Add a centred label to surface the most important aggregate value

Don't

  • Don't use a pie or donut chart for comparing precise values, use a bar chart instead
  • Don't label individual slices with both a legend and inline text, pick one