# Radial Chart Gauge

A 240-degree gauge arc showing an air quality reading with its value and rating below the center.

Radial Chart Gauge 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-gauge

**React**

**Example**

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

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

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

const chartData = [{ name: "value", value: 38, fill: "var(--color-value)" }]

const chartConfig = {
  value: { label: "Air quality", color: "var(--color-green-500)" },
} satisfies ChartConfig

export function RadialChartGauge() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Gauge</CardTitle>
        <CardDescription>Air quality index</CardDescription>
      </CardHeader>
      <CardContent>
        <div className="relative">
          <ChartContainer
            config={chartConfig}
            className="aspect-auto h-52 w-full"
          >
            <RadialBarChart
              accessibilityLayer={false}
              data={chartData}
              innerRadius="72%"
              outerRadius="100%"
              startAngle={210}
              endAngle={-30}
              barSize={14}
            >
              <PolarAngleAxis
                type="number"
                domain={[0, 100]}
                tick={false}
                axisLine={false}
              />
              <RadialBar
                dataKey="value"
                cornerRadius={20}
                background={{
                  fill: "color-mix(in oklab, var(--color-value) 22%, transparent)",
                }}
              />
            </RadialBarChart>
          </ChartContainer>
          <div className="pointer-events-none absolute inset-x-0 top-[44%] justify-center flex flex-col items-center text-center">
            <span className="text-3xl font-semibold tracking-tight tabular-nums">
              38
            </span>
            <span className="text-xs text-muted-foreground">Good</span>
          </div>
        </div>
      </CardContent>
    </Card>
  )
}
```

A gauge-style arc that opens at the bottom, showing a single reading with its value and rating in the center. Use it for scores with a known range, such as air quality, health scores or credit utilization.

## Installation

### CLI

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

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-gauge
```

### 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-gauge.tsx`:

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

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

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

const chartData = [{ name: "value", value: 38, fill: "var(--color-value)" }]

const chartConfig = {
  value: { label: "Air quality", color: "var(--color-green-500)" },
} satisfies ChartConfig

export function RadialChartGauge() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Gauge</CardTitle>
        <CardDescription>Air quality index</CardDescription>
      </CardHeader>
      <CardContent>
        <div className="relative">
          <ChartContainer
            config={chartConfig}
            className="aspect-auto h-52 w-full"
          >
            <RadialBarChart
              accessibilityLayer={false}
              data={chartData}
              innerRadius="72%"
              outerRadius="100%"
              startAngle={210}
              endAngle={-30}
              barSize={14}
            >
              <PolarAngleAxis
                type="number"
                domain={[0, 100]}
                tick={false}
                axisLine={false}
              />
              <RadialBar
                dataKey="value"
                cornerRadius={20}
                background={{
                  fill: "color-mix(in oklab, var(--color-value) 22%, transparent)",
                }}
              />
            </RadialBarChart>
          </ChartContainer>
          <div className="pointer-events-none absolute inset-x-0 top-[44%] justify-center flex flex-col items-center text-center">
            <span className="text-3xl font-semibold tracking-tight tabular-nums">
              38
            </span>
            <span className="text-xs text-muted-foreground">Good</span>
          </div>
        </div>
      </CardContent>
    </Card>
  )
}
```

4. Update the import paths to match your project.

## Usage

```tsx
import { RadialChartGauge } from "@/components/charts/radial-chart-gauge"
```

```tsx
<RadialChartGauge />
```

Set the reading in `chartData` and the scale on `PolarAngleAxis` through its `domain`. Update the number and rating text in the center overlay, which are not read from the data. Change the color in `chartConfig`, or pick it from the value if the color should signal good and bad ranges.

## Notes

There is no tooltip and the center text is hard-coded, so keep it in sync with the value you pass.

**React Native, SwiftUI, Jetpack Compose**

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

```tsx title="uniwind/components/charts/radial-chart-gauge.tsx"
import { View } from "react-native"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const chartData = [{ name: "value", value: 38 }]

const chartConfig = {
  value: { label: "Air quality", color: "green-500" },
} satisfies ChartConfig

export function RadialChartGauge() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Gauge</CardTitle>
        <CardDescription>Air quality index</CardDescription>
      </CardHeader>
      <CardContent>
        <View>
          <View
            pointerEvents="none"
            className="absolute inset-x-0 top-[44%] items-center"
          >
            <Text className="text-3xl font-semibold tracking-tight tabular-nums">
              38
            </Text>
            <Text className="text-xs text-muted-foreground">Good</Text>
          </View>
          <ChartContainer
            config={chartConfig}
            accessibilityLabel="Gauge"
            className="h-52 w-full"
          >
            <RadialBarChart
              data={chartData}
              innerRadius="72%"
              outerRadius="100%"
              startAngle={210}
              endAngle={-30}
              barSize={14}
            >
              <PolarAngleAxis domain={[0, 100]} />
              <RadialBar
                dataKey="value"
                cornerRadius={20}
                background={{ fillOpacity: 0.22 }}
              />
            </RadialBarChart>
          </ChartContainer>
        </View>
      </CardContent>
    </Card>
  )
}
```

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

private let chartConfig: ChartConfig = [
  "value": .init("Air quality", color: Palette.green500),
]

public struct RadialChartGauge: View {
  public init() {}

  public var body: some View {
    Card(.filled, size: .sm) {
      CardHeader("Gauge", description: "Air quality index")
      CardContent {
        ChartContainer(config: chartConfig) {
          RadialBarChart(
            [RadialBar("value", value: 38)],
            domain: 0...100,
            innerRadius: 0.72,
            outerRadius: 1,
            barSize: 14,
            startAngle: .degrees(-120),
            endAngle: .degrees(120),
            rounded: true,
            track: .tint
          )
          .overlay(alignment: .top) {
            VStack(spacing: 0) {
              Text(verbatim: "38")
                .textStyle(.xl3, weight: .semibold)
                .monospacedDigit()
              Text("Good")
                .textStyle(.xs)
                .foregroundStyle(EsuissColor.mutedForeground)
            }
            .multilineTextAlignment(.center)
            .padding(.top, 208 * 0.44)
          }
        }
        .frame(height: 208)
        .accessibilityElement(children: .ignore)
        .accessibilityLabel(Text("Gauge"))
        .accessibilityValue(Text("Air quality 38, Good"))
      }
    }
  }
}
```

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

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.text.font.FontWeight
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.RadialBarChart
import com.esuiss.ui.components.chartColor
import com.esuiss.ui.theme.EsuissTheme
import com.esuiss.ui.theme.Palette
import com.esuiss.ui.theme.Typography

private class RadialGaugeReading(val value: Double)

private val chartData = listOf(RadialGaugeReading(38.0))

private val chartConfig = ChartConfig(
    "value" to ChartConfigItem("Air quality") { Palette.green500 },
)

@Composable
fun RadialChartGauge(modifier: Modifier = Modifier) {
    val colors = EsuissTheme.colors
    Card(modifier, variant = CardVariant.Filled, size = CardSize.Sm) {
        CardHeader("Gauge", description = "Air quality index")
        CardContent {
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(208.dp),
            ) {
                ChartContainer(chartConfig, Modifier.matchParentSize()) {
                    val color = chartColor("value")
                    RadialBarChart(
                        chartData,
                        innerRadius = 0.72f,
                        outerRadius = 1f,
                        startAngle = 210f,
                        endAngle = -30f,
                        barSize = 14.dp,
                        accessibilityLabel = "Gauge, 38 Good",
                    ) {
                        PolarAngleAxis(0.0..100.0)
                        RadialBar("value", value = { it.value }, cornerRadius = 20.dp, background = color.copy(alpha = color.alpha * 0.22f))
                    }
                }
                Column(
                    Modifier
                        .align(Alignment.TopCenter)
                        .padding(top = 91.5.dp)
                        .clearAndSetSemantics {},
                    horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    BasicText(
                        "38",
                        style = Typography.xl3.copy(color = colors.foreground, fontWeight = FontWeight.SemiBold, fontFeatureSettings = "tnum"),
                    )
                    BasicText("Good", style = Typography.xs.copy(color = colors.mutedForeground))
                }
            }
        }
    }
}
```

A `RadialBarChart` drawn from 210 to -30 degrees, with a single value on a 0 to 100 `PolarAngleAxis` and a tinted track behind it. The number and its rating are `Text` layered over the arc. Nothing is interactive.

## Installation

**React Native**

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

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-gauge
```

**SwiftUI**

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

**Jetpack Compose**

```bash title="Terminal"
npx @esuiss/ui@latest add radial-chart-gauge --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), [Text](https://ui.suiss.app/docs/components/text).

### 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), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/radial-chart-gauge.tsx`:

- `uniwind/components/charts/radial-chart-gauge.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), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/radial-chart-gauge.tsx`:

```tsx title="nativewind/components/charts/radial-chart-gauge.tsx"
import { View } from "react-native"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"

const chartData = [{ name: "value", value: 38 }]

const chartConfig = {
  value: { label: "Air quality", color: "green-500" },
} satisfies ChartConfig

export function RadialChartGauge() {
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Gauge</CardTitle>
        <CardDescription>Air quality index</CardDescription>
      </CardHeader>
      <CardContent>
        <View>
          <View
            pointerEvents="none"
            className="absolute inset-x-0 top-[44%] items-center"
          >
            <Text className="text-3xl font-semibold tracking-tight tabular-nums">
              38
            </Text>
            <Text className="text-xs text-muted-foreground">Good</Text>
          </View>
          <ChartContainer
            config={chartConfig}
            accessibilityLabel="Gauge"
            className="h-52 w-full"
          >
            <RadialBarChart
              data={chartData}
              innerRadius="72%"
              outerRadius="100%"
              startAngle={210}
              endAngle={-30}
              barSize={14}
            >
              <PolarAngleAxis domain={[0, 100]} />
              <RadialBar
                dataKey="value"
                cornerRadius={20}
                background={{ fillOpacity: 0.22 }}
              />
            </RadialBarChart>
          </ChartContainer>
        </View>
      </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), [Text](https://ui.suiss.app/docs/components/text).

2. Copy the source into `components/charts/radial-chart-gauge.tsx`:

```tsx title="stylesheet/components/charts/radial-chart-gauge.tsx"
import { StyleSheet, View } from "react-native"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  type ChartConfig,
  ChartContainer,
  PolarAngleAxis,
  RadialBar,
  RadialBarChart,
} from "@/components/ui/chart"
import { Text } from "@/components/ui/text"
import { fontSize, useTheme } from "@/components/ui/theme"

const chartData = [{ name: "value", value: 38 }]

const chartConfig = {
  value: { label: "Air quality", color: "green-500" },
} satisfies ChartConfig

const styles = StyleSheet.create({
  overlay: {
    position: "absolute",
    left: 0,
    right: 0,
    top: "44%",
    alignItems: "center",
  },
  value: {
    ...fontSize["3xl"],
    fontWeight: "600",
    letterSpacing: -0.75,
    fontVariant: ["tabular-nums"],
  },
  caption: { ...fontSize.xs },
  chart: { height: 208 },
})

export function RadialChartGauge() {
  const { colors } = useTheme()
  return (
    <Card variant="filled" size="sm">
      <CardHeader>
        <CardTitle>Gauge</CardTitle>
        <CardDescription>Air quality index</CardDescription>
      </CardHeader>
      <CardContent>
        <View>
          <View pointerEvents="none" style={styles.overlay}>
            <Text style={styles.value}>38</Text>
            <Text style={[styles.caption, { color: colors.mutedForeground }]}>
              Good
            </Text>
          </View>
          <ChartContainer
            config={chartConfig}
            accessibilityLabel="Gauge"
            style={styles.chart}
          >
            <RadialBarChart
              data={chartData}
              innerRadius="72%"
              outerRadius="100%"
              startAngle={210}
              endAngle={-30}
              barSize={14}
            >
              <PolarAngleAxis domain={[0, 100]} />
              <RadialBar
                dataKey="value"
                cornerRadius={20}
                background={{ fillOpacity: 0.22 }}
              />
            </RadialBarChart>
          </ChartContainer>
        </View>
      </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/RadialChartGauge.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/RadialChartGauge.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 { RadialChartGauge } from "@/components/charts/radial-chart-gauge"
```

```tsx
<RadialChartGauge />
```

Change the `value` in `chartData` (0 to 100) and the centered text to match it; the label and color live in `chartConfig`. The component takes no props.

