# Radial Chart Tinted

Concentric radial bars whose unfilled track is a soft tint of each bar's own color.

Radial Chart Tinted 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/radial-chart-tinted

**React**

**Example**

```tsx title="components/charts/radial-chart-tinted.tsx"
"use client"

import { PolarAngleAxis, RadialBar, RadialBarChart } from "recharts"

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

const MAX = 320

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)" },
]

const tracks = chartData.map((item) => ({
  ...item,
  users: MAX,
  fill: `color-mix(in oklab, ${item.fill} 22%, transparent)`,
}))

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)" },
} satisfies ChartConfig

const shape = {
  innerRadius: "25%",
  outerRadius: "100%",
  barSize: 12,
} as const

export function RadialChartTinted() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Tinted track</CardTitle>
        <CardDescription>
          The unfilled part keeps a soft tint of its color
        </CardDescription>
      </CardHeader>
      <CardContent>
        <div className="relative h-52">
          <ChartContainer
            config={chartConfig}
            aria-hidden
            className="absolute inset-0 aspect-auto"
          >
            <RadialBarChart accessibilityLayer={false} data={tracks} {...shape}>
              <PolarAngleAxis
                type="number"
                domain={[0, MAX]}
                tick={false}
                axisLine={false}
              />
              <RadialBar
                dataKey="users"
                cornerRadius={10}
                isAnimationActive={false}
              />
            </RadialBarChart>
          </ChartContainer>
          <ChartContainer
            config={chartConfig}
            className="absolute inset-0 aspect-auto"
          >
            <RadialBarChart accessibilityLayer data={chartData} {...shape}>
              <PolarAngleAxis
                type="number"
                domain={[0, MAX]}
                tick={false}
                axisLine={false}
              />
              <ChartTooltip
                cursor={false}
                content={<ChartTooltipContent hideLabel nameKey="device" />}
              />
              <RadialBar dataKey="users" cornerRadius={10} />
            </RadialBarChart>
          </ChartContainer>
        </div>
      </CardContent>
    </Card>
  )
}
```

Concentric radial bars where the unfilled part of each track is a soft tint of the bar's own color instead of neutral gray. Choose it over the default radial chart for a more colorful look that still shows how far each bar has to go.

## Installation

### CLI

```bash title="Terminal"
npx shadcn@latest add @esuiss/radial-chart-tinted
```

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 radial-chart-tinted
```

### 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/radial-chart-tinted.tsx`:

```tsx title="components/charts/radial-chart-tinted.tsx"
"use client"

import { PolarAngleAxis, RadialBar, RadialBarChart } from "recharts"

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

const MAX = 320

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)" },
]

const tracks = chartData.map((item) => ({
  ...item,
  users: MAX,
  fill: `color-mix(in oklab, ${item.fill} 22%, transparent)`,
}))

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)" },
} satisfies ChartConfig

const shape = {
  innerRadius: "25%",
  outerRadius: "100%",
  barSize: 12,
} as const

export function RadialChartTinted() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Tinted track</CardTitle>
        <CardDescription>
          The unfilled part keeps a soft tint of its color
        </CardDescription>
      </CardHeader>
      <CardContent>
        <div className="relative h-52">
          <ChartContainer
            config={chartConfig}
            aria-hidden
            className="absolute inset-0 aspect-auto"
          >
            <RadialBarChart accessibilityLayer={false} data={tracks} {...shape}>
              <PolarAngleAxis
                type="number"
                domain={[0, MAX]}
                tick={false}
                axisLine={false}
              />
              <RadialBar
                dataKey="users"
                cornerRadius={10}
                isAnimationActive={false}
              />
            </RadialBarChart>
          </ChartContainer>
          <ChartContainer
            config={chartConfig}
            className="absolute inset-0 aspect-auto"
          >
            <RadialBarChart accessibilityLayer data={chartData} {...shape}>
              <PolarAngleAxis
                type="number"
                domain={[0, MAX]}
                tick={false}
                axisLine={false}
              />
              <ChartTooltip
                cursor={false}
                content={<ChartTooltipContent hideLabel nameKey="device" />}
              />
              <RadialBar dataKey="users" cornerRadius={10} />
            </RadialBarChart>
          </ChartContainer>
        </div>
      </CardContent>
    </Card>
  )
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { RadialChartTinted } from "@/components/charts/radial-chart-tinted"
```

```tsx
<RadialChartTinted />
```

Replace `chartData` and add each category to `chartConfig`; the tinted tracks are built from the same data. Set `MAX` to the value that should close a full ring, and keep it at or above your largest value.

## Notes

The tracks are a second chart layered behind the real one and hidden from assistive technology, so keep the sizing shared between both when you change it.

**React Native, SwiftUI, Jetpack Compose**

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

```tsx title="uniwind/components/charts/radial-chart-tinted.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  Cell,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"

const MAX = 320

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" },
} satisfies ChartConfig

type Device = "phone" | "laptop" | "tablet" | "watch"

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

export function RadialChartTinted() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Tinted track</CardTitle>
        <CardDescription>
          The unfilled part keeps a soft tint of its color
        </CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Tinted track"
          className="h-52 w-full"
        >
          <RadialBarChart
            data={chartData}
            innerRadius="25%"
            outerRadius="100%"
            barSize={12}
          >
            <PolarAngleAxis domain={[0, MAX]} />
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <RadialBar
              isAnimationActive={false}
              dataKey="users"
              cornerRadius={10}
              background={{ fillOpacity: 0.22 }}
            >
              {chartData.map((item) => (
                <Cell key={item.device} fill={chartConfig[item.device].color} />
              ))}
            </RadialBar>
          </RadialBarChart>
        </ChartContainer>
      </CardContent>
    </Card>
  )
}
```

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

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

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),
]

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

  public init() {}

  public var body: some View {
    Card(.filled, size: .sm) {
      CardHeader("Tinted track", description: "The unfilled part keeps a soft tint of its color")
      CardContent {
        ChartContainer(config: chartConfig) {
          RadialBarChart(
            chartData.map { RadialBar($0.device, value: $0.users) },
            domain: 0...320,
            innerRadius: 0.25,
            outerRadius: 1,
            barSize: 12,
            rounded: true,
            track: .tint,
            selection: $selection,
            accessibilityLabel: "Tinted track",
            isAnimationActive: false
          ) { payload in
            ChartTooltipContent(payload, hideLabel: true)
          }
        }
        .frame(height: 208)
      }
    }
  }
}
```

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

import androidx.compose.foundation.layout.Box
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.semantics.clearAndSetSemantics
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.ChartCell
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.RadialBarChart
import com.esuiss.ui.components.chartColor

private const val MAX = 320.0

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

private val chartData = listOf(
    RadialTintedDeviceUsers("phone", 275.0),
    RadialTintedDeviceUsers("laptop", 200.0),
    RadialTintedDeviceUsers("tablet", 187.0),
    RadialTintedDeviceUsers("watch", 173.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 },
)

@Composable
fun RadialChartTinted(modifier: Modifier = Modifier) {
    Card(modifier, variant = CardVariant.Filled, size = CardSize.Sm) {
        CardHeader("Tinted track", description = "The unfilled part keeps a soft tint of its color")
        CardContent {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(208.dp),
            ) {
                ChartContainer(
                    chartConfig,
                    Modifier
                        .matchParentSize()
                        .clearAndSetSemantics {},
                ) {
                    val tints = chartData.map { chartColor(it.device).let { color -> color.copy(alpha = color.alpha * 0.22f) } }
                    RadialBarChart(chartData, innerRadius = 0.25f, outerRadius = 1f, barSize = 12.dp) {
                        PolarAngleAxis(0.0..MAX)
                        RadialBar("users", value = { MAX }, nameKey = { it.device }, cornerRadius = 10.dp, cells = { index -> ChartCell(tints[index]) }, isAnimationActive = false)
                    }
                }
                ChartContainer(chartConfig, Modifier.matchParentSize()) {
                    RadialBarChart(
                        chartData,
                        innerRadius = 0.25f,
                        outerRadius = 1f,
                        barSize = 12.dp,
                        accessibilityLabel = "Tinted track",
                    ) {
                        PolarAngleAxis(0.0..MAX)
                        ChartTooltip { ChartTooltipContent(hideLabel = true) }
                        RadialBar("users", value = { it.users }, nameKey = { it.device }, cornerRadius = 10.dp)
                    }
                }
            }
        }
    }
}
```

A `RadialBarChart` with one bar per record in `chartData`, measured against a shared `MAX` of 320. Each bar is colored through `Cell`, and its background track uses the same color at low opacity. Pressing a bar shows a tooltip. The bars set `isAnimationActive={false}` and draw without the enter animation.

## Installation

**React Native**

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

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 radial-chart-tinted
```

**SwiftUI**

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

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add radial-chart-tinted --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/radial-chart-tinted.tsx`:

- `uniwind/components/charts/radial-chart-tinted.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/radial-chart-tinted.tsx`:

```tsx title="nativewind/components/charts/radial-chart-tinted.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  Cell,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"

const MAX = 320

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" },
} satisfies ChartConfig

type Device = "phone" | "laptop" | "tablet" | "watch"

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

export function RadialChartTinted() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Tinted track</CardTitle>
        <CardDescription>
          The unfilled part keeps a soft tint of its color
        </CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Tinted track"
          className="h-52 w-full"
        >
          <RadialBarChart
            data={chartData}
            innerRadius="25%"
            outerRadius="100%"
            barSize={12}
          >
            <PolarAngleAxis domain={[0, MAX]} />
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <RadialBar
              isAnimationActive={false}
              dataKey="users"
              cornerRadius={10}
              background={{ fillOpacity: 0.22 }}
            >
              {chartData.map((item) => (
                <Cell key={item.device} fill={chartConfig[item.device].color} />
              ))}
            </RadialBar>
          </RadialBarChart>
        </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/radial-chart-tinted.tsx`:

```tsx title="stylesheet/components/charts/radial-chart-tinted.tsx"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  Cell,
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"

const MAX = 320

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" },
} satisfies ChartConfig

type Device = "phone" | "laptop" | "tablet" | "watch"

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

export function RadialChartTinted() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Tinted track</CardTitle>
        <CardDescription>
          The unfilled part keeps a soft tint of its color
        </CardDescription>
      </CardHeader>
      <CardContent>
        <ChartContainer
          config={chartConfig}
          accessibilityLabel="Tinted track"
          style={{ height: 208 }}
        >
          <RadialBarChart
            data={chartData}
            innerRadius="25%"
            outerRadius="100%"
            barSize={12}
          >
            <PolarAngleAxis domain={[0, MAX]} />
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel nameKey="device" />}
            />
            <RadialBar
              isAnimationActive={false}
              dataKey="users"
              cornerRadius={10}
              background={{ fillOpacity: 0.22 }}
            >
              {chartData.map((item) => (
                <Cell key={item.device} fill={chartConfig[item.device].color} />
              ))}
            </RadialBar>
          </RadialBarChart>
        </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/RadialChartTinted.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/RadialChartTinted.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 { RadialChartTinted } from "@/components/charts/radial-chart-tinted"
```

```tsx
<RadialChartTinted />
```

Replace `chartData` with your records, set `MAX` to the top of your range, and add a matching entry per item to `chartConfig`. The component takes no props.

