Ring Chart

Animated concentric progress rings with staggered track and sweep entrances, a scale-up hover, a rolled center total, and a loading state.

Total

Daily Activity

  • Exercise2170%%
  • Steps8,30083%%
  • Calories54077%%

Installation

pnpm add @blakeui/pro-react
npm install @blakeui/pro-react
yarn add @blakeui/pro-react
bun add @blakeui/pro-react

Usage

RingChart is built on visx for its arc geometry and the motion library for the animation — it does not use Recharts, and it replaces the retired RadialChart. It is a single component: pass a data array (one {label, value, maxValue} per concentric ring, index 0 innermost) and configure everything through props. Each ring is a progress arc of value / maxValue over a full-circle track — tracks scale in staggered from the center, the value arcs sweep open after a hand-off, and hovering a ring scales it up while the others dim and the center rolls to that ring's value through the shared odometer. Ring colors come from the categorical --chart-1 … --chart-5 tokens in data order (override per-datum with color); the tracks and chrome map onto BlakeUI's neutral tokens automatically.

import {RingChart} from "@blakeui/pro-react";

const activity = [
  {label: "Exercise", value: 21, maxValue: 30},
  {label: "Steps", value: 8300, maxValue: 10000},
  {label: "Calories", value: 540, maxValue: 700},
];

function App() {
  return <RingChart data={activity} centerLabel="Total" />;
}

For a legend that highlights in sync with the chart, control the hover: pass hoveredIndex and onHoverChange, and drive both the chart and your legend rows from the same index (the hero demo above wires this in both directions).

Keyboard & motion

The chart is keyboard-accessible: focus it and use the arrow keys (or Home / End) to walk the rings; Escape clears the selection. The active ring is announced to screen readers through a live region. The entrance choreography, hover springs, and center odometer all respect prefers-reduced-motion — when it is set, the chart renders without animation.

Loading state

Set status="loading" to show a stroke-only skeleton ring while data resolves — a bright pulse laps the ring under a shimmering caption. Flip it to "ready" and the load→ready choreography plays: the pulse flows out, the caption exits, the tracks scale in, and the value arcs sweep around.

Loading activity…
Loading activity…
  • Exercise
  • Steps
  • Calories

API Reference

RingChart

The single chart component. Measures its container (or takes a fixed size), auto-scales the ring stack to fit, and renders the SVG plus the HTML center overlay.

PropTypeDefaultDescription
dataRingChartDataPoint[]One entry per concentric ring, index 0 innermost: {label, value, maxValue, color?}. Each ring fills value / maxValue of the circle; color overrides the positional --chart-1..5 assignment.
sizenumberFixed box size in px. Omit for responsive sizing (a square that fills the container width).
strokeWidthnumber12Ring thickness in design px (the whole stack auto-scales to fit the box).
ringGapnumber6Gap between concentric rings in design px.
baseInnerRadiusnumber60Inner radius of the innermost ring in design px.
lineCap"round" | "butt""round"Progress-arc end treatment — fully rounded caps or square ends.
startAnglenumber-Math.PI / 2Start angle in radians (0 = 12 o'clock, clockwise).
endAnglenumber(3 * Math.PI) / 2End angle in radians (the default closes a full lap from the top).
showGlowbooleantrueGlow the hovered ring with a drop-shadow in its own color.
centerLabelstring"Total"Label under the rolled total; hover swaps it for the active ring's label.
showCenterbooleantrueRender the rolled total + label inside the innermost ring.
valuePrefixstringStatic text rendered before the center value (e.g. "$").
hoveredIndexnumber | nullControlled hover — the active ring index. Pair with onHoverChange for legend sync.
onHoverChange(index: number | null) => voidCalled when the active ring changes (pointer, keyboard, or a controlled legend).
animationDurationnumber1100Per-stage entrance duration in ms (tracks stagger 80ms; sweeps hand off at 600ms + 100ms per ring).
status"loading" | "ready""ready"While loading, shows the skeleton ring and disables interaction. Flipping to ready plays the entrance.
loadingLabelstring""Centered caption shown while loading. Empty string hides it.

Also supports all native div HTML attributes.

On this page