# Pie Chart Nested

Two concentric pies: an inner ring of grouped totals surrounded by an outer ring of individual categories.

Pie Chart Nested is an open-source chart from suiss/ui for React, React Native, SwiftUI and Jetpack Compose. The @esuiss/ui CLI copies its source into your project, so you own the code.

Source: https://ui.suiss.app/docs/charts/pie-chart-nested

**React**

**Example**

```tsx title="components/charts/pie-chart-nested.tsx"
"use client"

import { Pie, PieChart } from "recharts"

import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from "@/components/ui/chart"

const chartData = [
  { device: "phone", users: 275, fill: "var(--color-phone)" },
  { device: "laptop", users: 200, fill: "var(--color-laptop)" },
  { device: "tablet", users: 187, fill: "var(--color-tablet)" },
  { device: "watch", users: 173, fill: "var(--color-watch)" },
  { device: "other", users: 90, fill: "var(--color-other)" },
]

const chartConfig = {
  users: { label: "Users" },
  phone: { label: "Phone", color: "var(--chart-1)" },
  laptop: { label: "Laptop", color: "var(--chart-2)" },
  tablet: { label: "Tablet", color: "var(--chart-3)" },
  watch: { label: "Watch", color: "var(--chart-4)" },
  other: { label: "Other", color: "var(--chart-5)" },
  personal: { label: "Phones and laptops", color: "var(--chart-1)" },
  companion: { label: "Tablets, watches and other", color: "var(--chart-4)" },
} satisfies ChartConfig

const groups = [
  { device: "personal", users: 475, fill: "var(--color-personal)" },
  { device: "companion", users: 450, fill: "var(--color-companion)" },
]

export function PieChartNested() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Nested</CardTitle>
        <CardDescription>Groups inside, details outside</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-52 w-full"
        >
          <PieChart accessibilityLayer>
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <Pie
              data={groups}
              dataKey="users"
              nameKey="device"
              outerRadius="52%"
              stroke="var(--muted)"
              strokeWidth={2}
              fillOpacity={0.55}
            />
            <Pie
              data={chartData}
              dataKey="users"
              nameKey="device"
              innerRadius="60%"
              outerRadius="86%"
              stroke="var(--muted)"
              strokeWidth={2}
            />
          </PieChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

Two concentric rings: a lighter inner pie of group totals surrounded by an outer ring of individual categories. Use it for two-level breakdowns, such as product lines and the products within them.

## Installation

### CLI

```bash title="Terminal"
npx shadcn@latest add @esuiss/pie-chart-nested
```

Works in any project with a `components.json`. See [Installation](https://ui.suiss.app/docs/installation#add-components) for the one-line registry setup. Or use the suiss/ui CLI:

```bash title="Terminal"
npx @esuiss/ui@latest add charts pie-chart-nested
```

### Manual

1. Install the dependencies:

```bash title="Terminal"
npm install recharts
```

2. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

3. Copy the source into `components/charts/pie-chart-nested.tsx`:

```tsx title="components/charts/pie-chart-nested.tsx"
"use client"

import { Pie, PieChart } from "recharts"

import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from "@/components/ui/chart"

const chartData = [
  { device: "phone", users: 275, fill: "var(--color-phone)" },
  { device: "laptop", users: 200, fill: "var(--color-laptop)" },
  { device: "tablet", users: 187, fill: "var(--color-tablet)" },
  { device: "watch", users: 173, fill: "var(--color-watch)" },
  { device: "other", users: 90, fill: "var(--color-other)" },
]

const chartConfig = {
  users: { label: "Users" },
  phone: { label: "Phone", color: "var(--chart-1)" },
  laptop: { label: "Laptop", color: "var(--chart-2)" },
  tablet: { label: "Tablet", color: "var(--chart-3)" },
  watch: { label: "Watch", color: "var(--chart-4)" },
  other: { label: "Other", color: "var(--chart-5)" },
  personal: { label: "Phones and laptops", color: "var(--chart-1)" },
  companion: { label: "Tablets, watches and other", color: "var(--chart-4)" },
} satisfies ChartConfig

const groups = [
  { device: "personal", users: 475, fill: "var(--color-personal)" },
  { device: "companion", users: 450, fill: "var(--color-companion)" },
]

export function PieChartNested() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Nested</CardTitle>
        <CardDescription>Groups inside, details outside</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          className="aspect-auto h-52 w-full"
        >
          <PieChart accessibilityLayer>
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <Pie
              data={groups}
              dataKey="users"
              nameKey="device"
              outerRadius="52%"
              stroke="var(--muted)"
              strokeWidth={2}
              fillOpacity={0.55}
            />
            <Pie
              data={chartData}
              dataKey="users"
              nameKey="device"
              innerRadius="60%"
              outerRadius="86%"
              stroke="var(--muted)"
              strokeWidth={2}
            />
          </PieChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { PieChartNested } from "@/components/charts/pie-chart-nested"
```

```tsx
<PieChartNested />
```

Put the detailed records in `chartData` and the group totals in `groups`, making sure each group total matches the sum of its categories. Order the outer categories so each group's members sit together, aligned with their inner slice.

## Notes

In the demo the inner groups reuse the Phone and Watch keys even though they combine several categories, so their tooltips read Phone and Watch. Give each group its own key and label in `chartConfig` to avoid confusion.

**React Native, SwiftUI, Jetpack Compose**

![Preview](https://ui.suiss.app/previews/charts-pie--nested.light.webp)

```tsx title="uniwind/components/charts/pie-chart-nested.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Pie,
  PieChart,
} from "@/components/ui/chart"

const chartData = [
  { device: "phone", users: 275 },
  { device: "laptop", users: 200 },
  { device: "tablet", users: 187 },
  { device: "watch", users: 173 },
  { device: "other", users: 90 },
]

const chartConfig = {
  users: { label: "Users" },
  phone: { label: "Phone", color: "chart-1" },
  laptop: { label: "Laptop", color: "chart-2" },
  tablet: { label: "Tablet", color: "chart-3" },
  watch: { label: "Watch", color: "chart-4" },
  other: { label: "Other", color: "chart-5" },
} satisfies ChartConfig

const groups = [
  { device: "phone", users: 475 },
  { device: "watch", users: 450 },
]

export function PieChartNested() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Nested</CardTitle>
        <CardDescription>Groups inside, details outside</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Nested"
          className="h-52 w-full"
        >
          <PieChart>
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <Pie
              data={groups}
              dataKey="users"
              nameKey="device"
              outerRadius="52%"
              stroke="muted"
              strokeWidth={2}
              fillOpacity={0.55}
            />
            <Pie
              data={chartData}
              dataKey="users"
              nameKey="device"
              innerRadius="60%"
              outerRadius="86%"
              stroke="muted"
              strokeWidth={2}
            />
          </PieChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

```swift title="swift/Charts/PieChartNested.swift"
import Charts
import SwiftUI

private let chartData: [(device: String, users: Double)] = [
  ("phone", 275), ("laptop", 200), ("tablet", 187), ("watch", 173), ("other", 90),
]

private let chartConfig: ChartConfig = [
  "users": .init("Users"),
  "phone": .init("Phone", color: EsuissColor.chart1),
  "laptop": .init("Laptop", color: EsuissColor.chart2),
  "tablet": .init("Tablet", color: EsuissColor.chart3),
  "watch": .init("Watch", color: EsuissColor.chart4),
  "other": .init("Other", color: EsuissColor.chart5),
]

private let groups: [(device: String, users: Double)] = [("phone", 475), ("watch", 450)]

public struct PieChartNested: View {
  @State private var selection: Int?

  public init() {}

  public var body: some View {
    Card(.filled, size: .sm) {
      CardHeader("Nested", description: "Groups inside, details outside")
      CardContent {
        ChartContainer(config: chartConfig) {
          ChartAnimator { progress in
            ZStack {
              Chart {
                ForEach(groups, id: \.device) { item in
                  SectorMark(angle: .value("Users", item.users * progress), outerRadius: .ratio(0.52), angularInset: 1)
                    .foregroundStyle(chartConfig.color(item.device).opacity(0.55))
                }
                ChartSectorRest(total: groups.reduce(0) { $0 + $1.users }, progress: progress)
              }
              .accessibilityHidden(true)
              Chart {
                ForEach(chartData, id: \.device) { item in
                  SectorMark(angle: .value("Users", item.users * progress), innerRadius: .ratio(0.6), outerRadius: .ratio(0.86), angularInset: 1)
                    .foregroundStyle(chartConfig.color(item.device))
                }
                ChartSectorRest(total: chartData.reduce(0) { $0 + $1.users }, progress: progress)
              }
              .chartTooltip(
                angle: chartData.map(\.users),
                labels: chartData.map { chartConfig.label($0.device) },
                outerRadius: 0.86,
                selection: $selection,
                accessibilityLabel: "Nested",
                items: { [ChartTooltipItem(chartData[$0].device, value: chartData[$0].users)] }
              ) { payload in
                ChartTooltipContent(payload, hideLabel: true)
              }
            }
            .padding(5)
          }
        }
        .frame(height: 208)
      }
    }
  }
}
```

```kt title="kotlin/charts/PieChartNested.kt"
package com.esuiss.ui.charts

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Card
import com.esuiss.ui.components.CardContent
import com.esuiss.ui.components.CardHeader
import com.esuiss.ui.components.CardSize
import com.esuiss.ui.components.CardVariant
import com.esuiss.ui.components.ChartConfig
import com.esuiss.ui.components.ChartConfigItem
import com.esuiss.ui.components.ChartContainer
import com.esuiss.ui.components.ChartTooltipContent
import com.esuiss.ui.components.PieChart
import com.esuiss.ui.theme.EsuissTheme

private class PieNestedDeviceUsers(val device: String, val users: Double)

private val chartData = listOf(
    PieNestedDeviceUsers("phone", 275.0),
    PieNestedDeviceUsers("laptop", 200.0),
    PieNestedDeviceUsers("tablet", 187.0),
    PieNestedDeviceUsers("watch", 173.0),
    PieNestedDeviceUsers("other", 90.0),
)

private val groups = listOf(
    PieNestedDeviceUsers("phone", 475.0),
    PieNestedDeviceUsers("watch", 450.0),
)

private val chartConfig = ChartConfig(
    "users" to ChartConfigItem("Users"),
    "phone" to ChartConfigItem("Phone") { chart1 },
    "laptop" to ChartConfigItem("Laptop") { chart2 },
    "tablet" to ChartConfigItem("Tablet") { chart3 },
    "watch" to ChartConfigItem("Watch") { chart4 },
    "other" to ChartConfigItem("Other") { chart5 },
)

@Composable
fun PieChartNested(modifier: Modifier = Modifier) {
    val colors = EsuissTheme.colors
    Card(modifier, variant = CardVariant.Filled, size = CardSize.Sm) {
        CardHeader("Nested", description = "Groups inside, details outside")
        CardContent {
            ChartContainer(
                chartConfig,
                Modifier
                    .fillMaxWidth()
                    .height(208.dp),
            ) {
                PieChart(accessibilityLabel = "Nested") {
                    ChartTooltip { ChartTooltipContent(hideLabel = true) }
                    Pie(
                        groups,
                        value = { it.users },
                        nameKey = { it.device },
                        outerRadius = 0.52f,
                        stroke = colors.muted,
                        strokeWidth = 2.dp,
                        fillOpacity = 0.55f,
                    )
                    Pie(
                        chartData,
                        value = { it.users },
                        nameKey = { it.device },
                        innerRadius = 0.6f,
                        outerRadius = 0.86f,
                        stroke = colors.muted,
                        strokeWidth = 2.dp,
                    )
                }
            }
        }
    }
}
```

A `PieChart` with two `Pie` layers. The inner pie reads a `groups` array and is drawn at reduced opacity; the outer ring reads `chartData`, one record per device. Pressing a slice in either ring shows a tooltip.

## Installation

**React Native**

```bash title="Terminal"
npx shadcn@latest add @esuiss-rn/pie-chart-nested
```

See [Installation](https://ui.suiss.app/docs/installation) for the `components.json` setup. Or use the suiss/ui CLI:

```bash title="Terminal"
npx @esuiss/ui@latest add pie-chart-nested
```

**SwiftUI**

```bash title="Terminal"
npx @esuiss/ui@latest add pie-chart-nested --platform swift
```

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add pie-chart-nested --platform kotlin
```

The CLI also adds what it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

### Manual

**React Native**

**Uniwind**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

2. Copy the source into `components/charts/pie-chart-nested.tsx`:

- `uniwind/components/charts/pie-chart-nested.tsx`: shown above

3. Update the import paths to match your project.

**NativeWind**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

2. Copy the source into `components/charts/pie-chart-nested.tsx`:

```tsx title="nativewind/components/charts/pie-chart-nested.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Pie,
  PieChart,
} from "@/components/ui/chart"

const chartData = [
  { device: "phone", users: 275 },
  { device: "laptop", users: 200 },
  { device: "tablet", users: 187 },
  { device: "watch", users: 173 },
  { device: "other", users: 90 },
]

const chartConfig = {
  users: { label: "Users" },
  phone: { label: "Phone", color: "chart-1" },
  laptop: { label: "Laptop", color: "chart-2" },
  tablet: { label: "Tablet", color: "chart-3" },
  watch: { label: "Watch", color: "chart-4" },
  other: { label: "Other", color: "chart-5" },
} satisfies ChartConfig

const groups = [
  { device: "phone", users: 475 },
  { device: "watch", users: 450 },
]

export function PieChartNested() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Nested</CardTitle>
        <CardDescription>Groups inside, details outside</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Nested"
          className="h-52 w-full"
        >
          <PieChart>
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <Pie
              data={groups}
              dataKey="users"
              nameKey="device"
              outerRadius="52%"
              stroke="muted"
              strokeWidth={2}
              fillOpacity={0.55}
            />
            <Pie
              data={chartData}
              dataKey="users"
              nameKey="device"
              innerRadius="60%"
              outerRadius="86%"
              stroke="muted"
              strokeWidth={2}
            />
          </PieChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

3. Update the import paths to match your project.

**StyleSheet**

1. Add the pieces it builds on: [Card](https://ui.suiss.app/docs/components/card), [Chart](https://ui.suiss.app/docs/components/chart).

2. Copy the source into `components/charts/pie-chart-nested.tsx`:

```tsx title="stylesheet/components/charts/pie-chart-nested.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  Pie,
  PieChart,
} from "@/components/ui/chart"

const chartData = [
  { device: "phone", users: 275 },
  { device: "laptop", users: 200 },
  { device: "tablet", users: 187 },
  { device: "watch", users: 173 },
  { device: "other", users: 90 },
]

const chartConfig = {
  users: { label: "Users" },
  phone: { label: "Phone", color: "chart-1" },
  laptop: { label: "Laptop", color: "chart-2" },
  tablet: { label: "Tablet", color: "chart-3" },
  watch: { label: "Watch", color: "chart-4" },
  other: { label: "Other", color: "chart-5" },
} satisfies ChartConfig

const groups = [
  { device: "phone", users: 475 },
  { device: "watch", users: 450 },
]

export function PieChartNested() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Nested</CardTitle>
        <CardDescription>Groups inside, details outside</CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Nested"
          style={{ height: 208 }}
        >
          <PieChart>
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <Pie
              data={groups}
              dataKey="users"
              nameKey="device"
              outerRadius="52%"
              stroke="muted"
              strokeWidth={2}
              fillOpacity={0.55}
            />
            <Pie
              data={chartData}
              dataKey="users"
              nameKey="device"
              innerRadius="60%"
              outerRadius="86%"
              stroke="muted"
              strokeWidth={2}
            />
          </PieChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

3. Update the import paths to match your project.

**SwiftUI**

1. Target iOS 17 or later.

2. Copy the theme files every view uses:

- `swift/Theme/Theme.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Theme/Theme.swift)

- `swift/Theme/Tokens.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Theme/Tokens.swift)

3. Copy the source and every file it uses:

- `swift/Charts/PieChartNested.swift`: shown above

- `swift/Components/Card.swift`: see [Card](https://ui.suiss.app/docs/components/card.md)

- `swift/Components/Chart.swift`: see [Chart](https://ui.suiss.app/docs/components/chart.md)

- `swift/Components/Haptics.swift`: see [Haptics](https://ui.suiss.app/docs/components/haptics.md)

- `swift/Components/Item.swift`: see [Item](https://ui.suiss.app/docs/components/item.md)

- `swift/Components/Separator.swift`: see [Separator](https://ui.suiss.app/docs/components/separator.md)

- `swift/Components/TextVariant.swift`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/swiftui/Sources/EsuissUI/Components/TextVariant.swift)

4. Add the files to your app target.

**Jetpack Compose**

1. Set `minSdk` to 24 or higher and add the dependencies:

```kotlin title="build.gradle.kts"
implementation(platform("androidx.compose:compose-bom:2026.09.00"))
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.ui:ui")
```

2. Copy the theme files every view uses:

- `kotlin/theme/Theme.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/theme/Theme.kt)

- `kotlin/theme/Tokens.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/theme/Tokens.kt)

3. Copy the source and every file it uses:

- `kotlin/charts/PieChartNested.kt`: shown above

- `kotlin/components/Card.kt`: see [Card](https://ui.suiss.app/docs/components/card.md)

- `kotlin/components/Chart.kt`: see [Chart](https://ui.suiss.app/docs/components/chart.md)

- `kotlin/components/Content.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/components/Content.kt)

- `kotlin/components/FormSupport.kt`: [source](https://github.com/e-suiss/ui/blob/main/packages/mobile/kotlin/ui/src/main/kotlin/com/esuiss/ui/components/FormSupport.kt)

- `kotlin/components/Haptics.kt`: see [Haptics](https://ui.suiss.app/docs/components/haptics.md)

- `kotlin/components/Icon.kt`: see [Icon](https://ui.suiss.app/docs/components/icon.md)

4. Update the `com.esuiss.ui` package names to match your project.

## Usage

```tsx
import { PieChartNested } from "@/components/charts/pie-chart-nested"
```

```tsx
<PieChartNested />
```

Replace `groups` and `chartData` with your summary and detail records, and add each name to `chartConfig` with its label and color. The component takes no props.

