# ProgressRing (/docs/charts/progress-ring)

A backup is 68% done and the only room for it is a tab header. ProgressRing draws that fraction as an arc from a start
angle fixed at 12 o'clock, with butt-cut caps: rounded caps overstate small fractions, and a variable start angle makes
identical fractions look different. It is not a gauge — no needle, no red zone.

```tsx
import { ProgressRing } from "@microcharts/react/progress-ring";

<ProgressRing value={0.68} label="percent" size={48} title="Backup" />
```

## Install

```tsx
import { ProgressRing } from "@microcharts/react/progress-ring";

<ProgressRing value={0.68} title="Backup" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.

## Try it

```tsx
import { ProgressRing } from "@microcharts/react/progress-ring/interactive";

<ProgressRing
  value={0.68}
  label="percent"
/>
```

## When to use it

Use it for tab headers, KPI card corners, and cooldowns or retry timers (`sweep`). For a precise read use Progress,
where the percent label is the datum.

## Sizing

**tab header**

```tsx
<span>Sync <ProgressRing value={0.68} style={{ width: "0.9em", height: "0.9em" }} /></span>
```

**cooldown (sweep)**

```tsx
// retry timer: the remaining wedge shrinks
<ProgressRing value={elapsed / total} sweep />
```

## Variants

```tsx
// the REMAINING wedge shrinks — cooldown semantics
<ProgressRing value={0.68} sweep />
```

```tsx
<ProgressRing value={0.68} weight={6} />
```

```tsx
<ProgressRing value={0.68} label="percent" locale="de-DE" />
```

## Edge cases

```tsx
<ProgressRing value={1.4} label="percent" title="Over budget" />
```

```tsx
<ProgressRing value={NaN} label="percent" title="Unknown" />
```

Past 100% the ring clamps full while the center label carries the true percent, the same contract as Progress. A
non-finite `value` announces no data instead of a fraction. A full circle is drawn as two half-arcs, since SVG cannot
draw a single 360° arc.

## Four homes

**In a sentence**

```tsx
<p>
  Nightly backup is{" "}
  <span className="mc-inline">
    <ProgressRing value={0.68} style={{ width: 18, height: 18 }} summary={false} />
  </span>{" "}
  two-thirds through.
</p>
```

**In a table cell**

```tsx
<td>
  <ProgressRing value={0.82} style={{ width: 18, height: 18 }} />
</td>
```

**In a KPI card**

```tsx
<div className="kpi">
  <span className="figure">142</span>
  <span className="unit">of 200 GB</span>
  <ProgressRing value={0.71} style={{ width: 32, height: 32 }} />
</div>
```

**In a tab header**

```tsx
<button className="tab">
  Photos <ProgressRing value={0.4} sweep style={{ width: 14, height: 14 }} />
</button>
```

## Accessibility

The accessible name reuses the progress wording — **"68% complete."**, or **"32% remaining."** in sweep mode. The
interactive entry announces only at 25/50/75/100% threshold crossings, so a streaming value never spams the screen
reader.

This chart is a single unit, so there is nothing to rove between: a click, tap, `Enter` or `Space` selects it
and fires `onSelect`, and no selection stays pinned. That is the scalar half of the shared
[interaction contract](/docs/accessibility#one-interaction-contract).
Hover or focus also reveals the reading itself in a floating chip, for the sizes and label modes where the mark
does not print it; `readout={false}` drops the chip and keeps everything else.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `value` (required) | `number` | The progressed amount. |
| `max` | `number` | Denominator (default 1). |
| `sweep` | `boolean` | Countdown: the REMAINING wedge shrinks. |
| `weight` | `number` | Ring thickness (viewBox units). |
| `label` | `"none" \| "percent"` | Centered figure (≥ 20 px rendered). |
| `size` | `number` | Ring box edge in viewBox units (default 24). |
| `animate` | `boolean` | (interactive) Opt-in entrance motion when the chart mounts client-side — add `import "@microcharts/react/motion"` once. Inert on the server, on hydrated server HTML, and under `prefers-reduced-motion`. |

Plus the shared grammar — `data`, `domain`, `color`, `title`, `summary`, `format` — and the layout props (`width`, `height`, `className`, `style`) that every chart accepts. Interactive entries also share `animate` and `live`, and — wherever a chart has more than one navigable unit — `onActive`, `onSelect`, `selectedIndex` and `defaultSelectedIndex`; and — wherever the chart shows a hover value — `readout`. See [the shared grammar](/docs/quickstart#the-shared-grammar).
