---
title: Pie Blocks
description: Ready-made pie chart blocks, powered by Apache ECharts
image: /og/og-image.png
---

## Market Share

### Market Share

```tsx
"use client";

import { EChartsPieChart, type ChartConfig } from "@/components/evilcharts/charts/echarts-pie-chart";
import { cn } from "@/lib/utils";
import { useState } from "react";

const SERIES = [
  { key: "skyline", label: "Skyline", value: 27, swatch: "bg-[#0a0a0a] dark:bg-[#ffffff]" },
  { key: "datawell", label: "Datawell", value: 21, swatch: "bg-[#262626] dark:bg-[#dedede]" },
  { key: "cloudpeak", label: "Cloudpeak", value: 13, swatch: "bg-[#3d3d3d] dark:bg-[#bebebe]" },
  { key: "taskbridge", label: "Taskbridge", value: 21, swatch: "bg-[#545454] dark:bg-[#a0a0a0]" },
  { key: "insightloop", label: "Insightloop", value: 6, swatch: "bg-[#6b6b6b] dark:bg-[#868686]" },
  {
    key: "streamforge",
    label: "Streamforge",
    value: 12,
    swatch: "bg-[#7d7d7d] dark:bg-[#6f6f6f]",
  },
] as const;

const chartData = [...SERIES].reverse().map(({ key, value }) => ({
  product: key,
  value,
  share: `${value}%`,
}));

const chartConfig = {
  skyline: { label: "Skyline", colors: { light: ["#0a0a0a"], dark: ["#ffffff"] } },
  datawell: { label: "Datawell", colors: { light: ["#262626"], dark: ["#dedede"] } },
  cloudpeak: { label: "Cloudpeak", colors: { light: ["#3d3d3d"], dark: ["#bebebe"] } },
  taskbridge: { label: "Taskbridge", colors: { light: ["#545454"], dark: ["#a0a0a0"] } },
  insightloop: { label: "Insightloop", colors: { light: ["#6b6b6b"], dark: ["#868686"] } },
  streamforge: { label: "Streamforge", colors: { light: ["#7d7d7d"], dark: ["#6f6f6f"] } },
} satisfies ChartConfig;

const TOTAL = SERIES.reduce((sum, { value }) => sum + value, 0);

export function EChartsMarketSharePieChart() {
  const [selected, setSelected] = useState<string | null>(null);

  return (
    <div className="flex h-full w-full flex-col p-4">
      <div className="relative min-h-0 w-full flex-1">
        <EChartsPieChart
          data={chartData}
          config={chartConfig}
          dataKey="value"
          nameKey="product"
          className="h-full w-full"
          selectedSector={selected}
          onSelectionChange={(selection) => setSelected(selection?.dataKey ?? null)}
        >
          <EChartsPieChart.Tooltip />
          <EChartsPieChart.Pie
            isClickable
            innerRadius="52%"
            outerRadius="94%"
            paddingAngle={3}
            startAngle={90}
            endAngle={-270}
          >
            <EChartsPieChart.Label dataKey="share" />
          </EChartsPieChart.Pie>
        </EChartsPieChart>

        <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-0.5">
          <span className="text-primary text-xl font-semibold tracking-tight sm:text-3xl">
            ${TOTAL}B
          </span>
          <span className="text-muted-foreground text-[10px] sm:text-xs">Ecosystem value</span>
        </div>
      </div>

      <div className="border-border mt-3 grid grid-flow-col grid-cols-2 grid-rows-3 gap-x-6 gap-y-1.5 border-t pt-3">
        {SERIES.map(({ key, label, value, swatch }) => (
          <button
            key={key}
            type="button"
            aria-pressed={selected === key}
            onClick={() => setSelected((prev) => (prev === key ? null : key))}
            className={cn(
              "flex cursor-pointer items-center gap-2 text-left text-xs transition-opacity",
              selected !== null && selected !== key && "opacity-40",
            )}
          >
            <span className={cn("size-3 shrink-0 rounded-[3px]", swatch)} />
            <span className="text-primary font-medium">{label}</span>
            <span className="text-muted-foreground">${value}B</span>
            <span className="text-muted-foreground/60">({value}%)</span>
          </button>
        ))}
      </div>
    </div>
  );
}

```
### npm

```bash
npx shadcn@latest add @evilcharts/market-share-echarts-pie-chart
```

### yarn

```bash
yarn shadcn@latest add @evilcharts/market-share-echarts-pie-chart
```

### bun

```bash
bunx --bun shadcn@latest add @evilcharts/market-share-echarts-pie-chart
```

### pnpm

```bash
pnpm dlx shadcn@latest add @evilcharts/market-share-echarts-pie-chart
```

## Progress Rings

### Progress Rings

```tsx
"use client";

import { EChartsPieChart, type ChartConfig } from "@/components/evilcharts/charts/echarts-pie-chart";

const DOT_COUNT = 40;
const SECTORS = DOT_COUNT * 2;

const STATS = [
  { id: "support", value: 48, caption: "Additional support requests from users." },
  { id: "forecast", value: 67, caption: "Inaccurate forecasts disrupt planning." },
] as const;

const FILLED = { light: ["#E43861"], dark: ["#E43861"] };
const TRACK = { light: ["#d4d4d4"], dark: ["#3f3f3f"] };
const GAP = { light: ["transparent"], dark: ["transparent"] };

const dotsFor = (value: number) => Math.round((DOT_COUNT * value) / 100);

const chartData = (id: string) =>
  Array.from({ length: SECTORS }, (_, i) => ({ dot: `${id}-${i}`, value: 1 }));

const chartConfig = (id: string, value: number): ChartConfig =>
  Object.fromEntries(
    Array.from({ length: SECTORS }, (_, i) => {
      const colors = i % 2 ? GAP : i / 2 < dotsFor(value) ? FILLED : TRACK;
      return [`${id}-${i}`, { label: "", colors }];
    }),
  );

export function EChartsProgressRingsPieChart() {
  return (
    <div className="flex h-full w-full flex-col p-4">
      <div className="flex items-start justify-between gap-4">
        <div className="flex flex-col gap-0.5">
          <span className="text-muted-foreground text-[10px] tracking-wide uppercase">
            User research
          </span>
          <span className="text-primary text-base leading-tight font-medium tracking-tight sm:text-xl">
            Where the workday leaks
          </span>
        </div>
        <span className="text-muted-foreground shrink-0 text-[10px] sm:text-xs">
          1,240 responses
        </span>
      </div>

      <div className="mt-3 grid min-h-0 flex-1 grid-cols-2 gap-4">
        {STATS.map(({ id, value, caption }) => (
          <div key={id} className="relative min-h-0">
            <EChartsPieChart
              data={chartData(id)}
              config={chartConfig(id, value)}
              dataKey="value"
              nameKey="dot"
              className="h-full w-full"
            >
              <EChartsPieChart.Pie
                innerRadius="85%"
                outerRadius="92%"
                paddingAngle={0}
                cornerRadius={6}
                startAngle={90}
                endAngle={-270}
              />
            </EChartsPieChart>

            <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-1 bg-[radial-gradient(circle_closest-side,rgba(0,0,0,0.04)_0_79%,transparent_79%)] px-[25%] text-center dark:bg-[radial-gradient(circle_closest-side,rgba(255,255,255,0.05)_0_79%,transparent_79%)]">
              <span className="text-primary text-2xl leading-none font-medium tracking-tight sm:text-4xl">
                {value}%
              </span>
              <span className="text-muted-foreground text-[10px] leading-snug text-balance sm:text-xs">
                {caption}
              </span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

```
### npm

```bash
npx shadcn@latest add @evilcharts/progress-rings-echarts-pie-chart
```

### yarn

```bash
yarn shadcn@latest add @evilcharts/progress-rings-echarts-pie-chart
```

### bun

```bash
bunx --bun shadcn@latest add @evilcharts/progress-rings-echarts-pie-chart
```

### pnpm

```bash
pnpm dlx shadcn@latest add @evilcharts/progress-rings-echarts-pie-chart
```

## Revenue Mix

### Revenue Mix

```tsx
"use client";

import { EChartsPieChart, type ChartConfig } from "@/components/evilcharts/charts/echarts-pie-chart";
import { cn } from "@/lib/utils";

const chartData = [
  {
    channel: "direct",
    label: "Direct",
    value: 52400,
    swatch: "bg-[#7c3aed] dark:bg-[#a78bfa]",
  },
  {
    channel: "marketplace",
    label: "Marketplace",
    value: 38900,
    swatch: "bg-[#4f46e5] dark:bg-[#818cf8]",
  },
  {
    channel: "wholesale",
    label: "Wholesale",
    value: 24150,
    swatch: "bg-[#0284c7] dark:bg-[#38bdf8]",
  },
  {
    channel: "affiliate",
    label: "Affiliate",
    value: 16300,
    swatch: "bg-[#059669] dark:bg-[#34d399]",
  },
];

const chartConfig = {
  direct: {
    label: "Direct",
    colors: { light: ["#7c3aed", "#a855f7"], dark: ["#a78bfa", "#c4b5fd"] },
  },
  marketplace: {
    label: "Marketplace",
    colors: { light: ["#4f46e5", "#6366f1"], dark: ["#818cf8", "#a5b4fc"] },
  },
  wholesale: {
    label: "Wholesale",
    colors: { light: ["#0284c7", "#0ea5e9"], dark: ["#38bdf8", "#7dd3fc"] },
  },
  affiliate: {
    label: "Affiliate",
    colors: { light: ["#059669", "#10b981"], dark: ["#34d399", "#6ee7b7"] },
  },
} satisfies ChartConfig;

const ORDERS = 1284;

const money = (value: number) => value.toLocaleString("en-US");

export function EChartsRevenueMixPieChart() {
  return (
    <div className="flex h-full w-full items-center gap-3 p-4 sm:gap-6">
      <div className="relative aspect-square w-[40%] max-w-72 shrink-0">
        <EChartsPieChart
          data={chartData}
          config={chartConfig}
          dataKey="value"
          nameKey="channel"
          className="h-full w-full"
        >
          <EChartsPieChart.Tooltip />
          <EChartsPieChart.Pie
            innerRadius="62%"
            outerRadius="92%"
            paddingAngle={6}
            cornerRadius={12}
            startAngle={90}
            endAngle={-270}
          />
        </EChartsPieChart>

        <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
          <div className="border-border flex aspect-square w-[56%] flex-col items-center justify-center rounded-full border border-dashed">
            <span className="text-primary text-lg leading-none font-semibold tracking-tight sm:text-2xl">
              {money(ORDERS)}
            </span>
            <span className="text-muted-foreground mt-1 text-[10px] sm:text-xs">Total orders</span>
          </div>
        </div>
      </div>

      <div className="flex min-h-0 min-w-0 flex-1 flex-col justify-center">
        {chartData.map(({ channel, label, value, swatch }) => (
          <div key={channel} className="flex items-center gap-2 py-1.5 sm:py-2">
            <span className={cn("size-2.5 shrink-0 rounded-[3px]", swatch)} />
            <span className="text-muted-foreground truncate text-xs">{label}</span>
            <span className="text-primary ml-auto text-xs font-semibold">${money(value)}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

```
### npm

```bash
npx shadcn@latest add @evilcharts/revenue-mix-echarts-pie-chart
```

### yarn

```bash
yarn shadcn@latest add @evilcharts/revenue-mix-echarts-pie-chart
```

### bun

```bash
bunx --bun shadcn@latest add @evilcharts/revenue-mix-echarts-pie-chart
```

### pnpm

```bash
pnpm dlx shadcn@latest add @evilcharts/revenue-mix-echarts-pie-chart
```

## Reliability Score

### Reliability Score

```tsx
"use client";

import { EChartsPieChart, type ChartConfig } from "@/components/evilcharts/charts/echarts-pie-chart";
import { cn } from "@/lib/utils";

const MAX = 1000;
const SCORE = 842;
const START_ANGLE = 210;

const chartData = [
  { band: "atrisk", label: "At risk", from: 0, value: 450, bar: "bg-[#e11d48] dark:bg-[#fb7185]" },
  { band: "fair", label: "Fair", from: 450, value: 200, bar: "bg-[#f59e0b] dark:bg-[#fbbf24]" },
  { band: "good", label: "Good", from: 650, value: 170, bar: "bg-[#84cc16] dark:bg-[#a3e635]" },
  {
    band: "excellent",
    label: "Excellent",
    from: 820,
    value: 180,
    bar: "bg-[#059669] dark:bg-[#34d399]",
  },
];

const chartConfig = {
  atrisk: { label: "At risk", colors: { light: ["#e11d48"], dark: ["#fb7185"] } },
  fair: { label: "Fair", colors: { light: ["#f59e0b"], dark: ["#fbbf24"] } },
  good: { label: "Good", colors: { light: ["#84cc16"], dark: ["#a3e635"] } },
  excellent: { label: "Excellent", colors: { light: ["#059669"], dark: ["#34d399"] } },
} satisfies ChartConfig;

const BAND = [...chartData].reverse().find(({ from }) => SCORE >= from) ?? chartData[0];

export function EChartsReliabilityScorePieChart() {
  return (
    <div className="flex h-full w-full flex-col p-4">
      <span className="text-primary text-base font-medium tracking-tight sm:text-lg">
        Delivery Reliability
      </span>

      <div className="relative mx-auto mt-1 aspect-square w-full max-w-50 shrink-0">
        <EChartsPieChart
          data={[...chartData].reverse()}
          config={chartConfig}
          dataKey="value"
          nameKey="band"
          className="h-full w-full"
        >
          <EChartsPieChart.Pie
            innerRadius="74%"
            outerRadius="94%"
            paddingAngle={6}
            cornerRadius={10}
            startAngle={-30}
            endAngle={START_ANGLE}
          />
        </EChartsPieChart>

        <svg
          viewBox="0 0 100 100"
          className="text-muted-foreground/50 pointer-events-none absolute inset-0"
          aria-hidden
        >
          <path
            d="M 23.15 65.5 A 31 31 0 1 1 76.85 65.5"
            fill="none"
            stroke="currentColor"
            strokeWidth="1"
            strokeLinecap="round"
            strokeDasharray="0.1 5"
          />
        </svg>
        <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
          <span className="text-primary text-3xl font-semibold tracking-tight sm:text-4xl">
            {SCORE}
          </span>
        </div>
      </div>

      <div className="-mt-6 text-center">
        <p className="text-primary text-xs font-medium sm:text-sm">
          Reliability is {BAND.label.toLowerCase()}
        </p>
        <p className="text-muted-foreground text-[10px] sm:text-xs">Updated 12 Mar 2026</p>
      </div>

      <div className="mt-auto shrink-0 pt-2">
        <div className="text-muted-foreground flex text-[10px]">
          {chartData.map(({ band, from, value }) => (
            <span key={band} style={{ flexGrow: value, flexBasis: 0 }}>
              {from}
            </span>
          ))}
          <span>{MAX}</span>
        </div>
        <div className="mt-1 flex gap-1">
          {chartData.map(({ band, bar, value }) => (
            <span
              key={band}
              className={cn("h-1.5 rounded-full", bar)}
              style={{ flexGrow: value, flexBasis: 0 }}
            />
          ))}
        </div>
      </div>
    </div>
  );
}

```
### npm

```bash
npx shadcn@latest add @evilcharts/reliability-score-echarts-pie-chart
```

### yarn

```bash
yarn shadcn@latest add @evilcharts/reliability-score-echarts-pie-chart
```

### bun

```bash
bunx --bun shadcn@latest add @evilcharts/reliability-score-echarts-pie-chart
```

### pnpm

```bash
pnpm dlx shadcn@latest add @evilcharts/reliability-score-echarts-pie-chart
```
