Acronis UIKit
Components

RadialBarChart

A typed radial bar chart — concentric arcs or a gauge.

Usage

import { RadialBarChart } from '@acronis-platform/ui-react';
import type { ChartConfig } from '@acronis-platform/ui-react';

RadialBarChart is a typed composition over the shared Chart primitives. Give it data, a per-arc config, the value field (dataKey), and the label field (nameKey) — it renders a themed recharts radial bar chart (concentric arcs, an optional background track, tooltip, and legend), so you don't hand-compose recharts children.

Each data row becomes a concentric arc (like a pie's slices unrolled into rings). Arc colors come from the palette prop, not from config — see Palettes. Each config entry, keyed by a nameKey value, maps that arc to a label and an optional tone that re-points it within the palette. RadialBarChart resolves them into the --color-<name> custom properties its arcs fill from.

Examples

Concentric arcs sweeping a full circle, with a background track, tooltip and legend:

const data = [
  { browser: 'Chrome', value: 65 },
  { browser: 'Safari', value: 50 },
  { browser: 'Firefox', value: 35 },
  { browser: 'Edge', value: 25 },
];

const config = {
  Chrome: { label: 'Chrome' },
  Safari: { label: 'Safari' },
  Firefox: { label: 'Firefox' },
  Edge: { label: 'Edge' },
} satisfies ChartConfig;

<RadialBarChart
  config={config}
  data={data}
  dataKey="value"
  nameKey="browser"
  className="h-[360px] w-[360px]"
/>;

Make a half-circle gauge with startAngle / endAngle:

<RadialBarChart config={config} data={data} dataKey="value" nameKey="browser" startAngle={180} endAngle={0} />

The order of the two angles is the sweep's direction — 90 → -270 runs clockwise, -270 → 90 counter-clockwise.

Tune the radii (innerRadius / outerRadius), cornerRadius, and toggle the showBackground track / showTooltip / showLegend. showPolarGrid adds the concentric grid behind the arcs, and cx / cy / barSize / barGap / barCategoryGap / margin place and size the ring itself.

Gauges

A gauge needs a scale. Without valueDomain, every arc is drawn relative to the largest value in the data — so a single value always fills the whole sweep, which is never what a gauge means. Give it the metric's own range and the arc becomes that fraction of the sweep, over the showBackground track:

<RadialBarChart
  config={{ Used: { label: 'Used' } }}
  data={[{ metric: 'Used', value: 65 }]}
  dataKey="value"
  nameKey="metric"
  valueDomain={[0, 100]}
  startAngle={180}
  endAngle={0}
  innerRadius={80}
  outerRadius={130}
  cy={190}
  centerLabel={{ value: '65%', label: 'of quota used' }}
  showLegend={false}
  className="h-[240px] w-[360px]"
/>

centerLabel puts the readout in the hole — a headline value and/or a label caption. Give innerRadius enough room to hold the text; it isn't clipped to the hole. For a half sweep, cy moves the baseline down so the drawn half fills its box.

minAngle floors a tiny arc (in degrees) so it stays visible and hoverable. The floor applies to a 0 too, which then reads as a small positive value — leave it unset when a metric can legitimately be zero.

Segmented gauge

segments cuts a single-value gauge's ring into equal segments, notched apart by segmentGap degrees:

<RadialBarChart
  config={{ criteria: { label: 'Criteria met' } }}
  data={[{ criteria: 'criteria', value: 29 }]}
  dataKey="value"
  nameKey="criteria"
  valueDomain={[0, 38]}
  segments={8}
  segmentGap={4}
  innerRadius={88}
  outerRadius={120}
  centerLabel={{ value: 29, label: '/ 38 criteria met' }}
  className="h-[360px] w-[360px]"
/>

The segments up to the value take the arc's color and the rest the muted track, so showBackground plays no part. The notches are geometry rather than data rows, which is why the arc labels and the legend are suppressed — so centerLabel is the chart's only always-visible reading here, not decoration. Give it the value and its scale. The tooltip stays and reports the metric (with the valueDomain maximum when there is one) wherever on the ring it's hovered, but a hover-only tooltip can't be the only place a value exists.

Segments only apply to a single-value gauge. Anything else falls back to the normal concentric arcs, legend included, rather than erroring: more than one row, dataKeys set, fewer than two segments, or a dataKey value that isn't a number (a stringified "29" off an API).

A valueDomain that can't place a value — no span ([n, n]) or inverted ([max, min]) — draws the ring as all track. A gauge that can't read its scale reports no progress rather than guessing at one.

Multi-metric

dataKeys plots one arc per metric instead of one per row. Colors and legend labels then come from config keyed by the metric key — the same convention as the cartesian charts — while nameKey names the band they share:

<RadialBarChart
  config={{
    used: { label: 'Used' },
    quota: { label: 'Quota' },
  }}
  data={[{ tier: 'Production', used: 72, quota: 90 }]}
  dataKeys={['used', 'quota']}
  dataKey="used"
  nameKey="tier"
  valueDomain={[0, 100]}
  startAngle={180}
  endAngle={0}
  cy={190}
  className="h-[260px] w-[380px]"
/>

Every metric shares one angular scale, so pass valueDomain when they're measured against a known maximum — otherwise they're scaled against the largest value present and the biggest arc always looks complete.

Custom tooltip

Replace the tooltip with a configured ChartTooltipContent — imported from the same library, so you never compose recharts yourself. Its formatter renders each row and labelFormatter the header, giving you custom formatting, per-series content, and extra fields:

import { RadialBarChart, ChartTooltipContent } from '@acronis-platform/ui-react';

<RadialBarChart
  config={config}
  data={data}
  dataKey="value"
  nameKey="browser"
  tooltipContent={
    <ChartTooltipContent
      nameKey="browser"
      hideLabel
      formatter={(value, name) => `${name}: ${value.toLocaleString()} users`}
    />
  }
/>;

Animation

Charts render statically by default. Opt in to an entrance animation with animate, and tune it with animationDuration / animationBegin / animationEasing:

<RadialBarChart config={config} data={data} dataKey="visitors" nameKey="browser" animate animationDuration={800} animationEasing="ease-out" />

animate honors prefers-reduced-motion: for a visitor who has asked their system to reduce motion, the series render at their final geometry with no animation (the same applies when rendering on the server).

Data labels

Annotate each point with its value using showLabels. labelFormatter takes the same formatters as the axes, so a label and its axis read alike:

<RadialBarChart config={config} data={data} dataKey="visitors" nameKey="browser" showLabels labelFormatter={formatCompactNumber} />

Labels sit insideStart by default — inside the arc, in a token that stays legible over a saturated series colour. labelPosition takes the polar placements: outside, center, centerTop, centerBottom, insideStart, insideEnd, end; outside moves them onto the chart surface instead:

<RadialBarChart config={config} data={data} dataKey="visitors" nameKey="browser" showLabels labelPosition="outside" />

labelFormat decides what a label reads — value (the default) or name-value, which prefixes the arc's name (its nameKey value, or the metric's config label in multi-metric mode). A name-value label is long and recharts curves it along its arc, so give the innermost arc enough circumference to hold it:

<RadialBarChart config={config} data={data} dataKey="visitors" nameKey="browser" showLabels labelFormat="name-value" innerRadius={70} />

Labels are off by default — with more than one series they collide easily, so turn them on for a single series or a chart with room to spare.

Accessibility

RadialBarChart sets no role and no aria-* of its own, and the SVG the arcs are drawn into has no accessible name. That gap belongs to this component rather than recharts: recharts takes title, desc and role as first-class chart props and writes them straight into the plot's <svg>, but RadialBarChart passes none of them down — it spreads the props you give it onto its own root <div> and hands the recharts chart only the data it computes itself, so the <title> / <desc> pair recharts always emits stays empty. recharts' accessibility layer is on by default and is not switched off here, so the plot is also a tab stop carrying role="application": a focus stop that announces neither a name nor any data. The component exposes no way to turn that off.

So put the name on the root, which spreads the props you pass. Choose the role before copying the snippet: role="img" names the chart but also makes its subtree presentational, and it does not remove the focusable plot inside it — wrapping the chart in a <figure> with a <figcaption> is often the better fit here. aria-labelledby works the same way as aria-label.

<RadialBarChart
  role="img"
  aria-label="Share of sessions: Chrome 65, Safari 50, Firefox 35, Edge 25"
  config={config}
  data={data}
  dataKey="value"
  nameKey="browser"
/>

Either way, a name is not a text alternative. A ring of arcs is a visual encoding of numbers, so the numbers themselves have to be reachable as text — a caption, a summary sentence, or a table beside the chart. The legend and the tooltip are ordinary HTML laid out beside the SVG rather than inside it, so the legend already names every arc in the document; the arc labels (showLabels) and the centerLabel readout are real <text> rather than pixels, but they sit in the SVG with no structural role. A segmented gauge is the case to watch: it suppresses both the arc labels and the legend, so the only reading it renders is centerLabel inside the SVG and a hover-only tooltip — give the value and its scale a home in text outside the chart as well.

Direction (RTL)

Under dir="rtl" the chrome around the plot — the legend, the tooltip, and any readouts you compose alongside them — mirrors on its own, because it is ordinary flow layout built from logical CSS utilities. The plot area deliberately stays left-to-right: recharts places every mark in physical SVG coordinates, so mirroring it would flip the reading order of the data without flipping the geometry that encodes it. ChartContainer holds that in place by pinning .recharts-surface to direction: ltr. Most of this chart doesn't need the pin: the sweep from startAngle to endAngle keeps its direction whatever the page does, a segmented ring's notches are geometry, the angular axis draws no ticks, and the centerLabel is anchored middle.

The arc labels are the part that does. showLabels draws each one along a <textPath> following its arc, with no anchor set, so it takes SVG's default text-anchor: start — which is direction-relative, and under an inherited dir="rtl" would start the text from the other end of the arc. The pin keeps them running from the start of the sweep. It stops at the surface, so the legend and the tooltip — HTML outside it — still mirror with the page.

API Reference

Prop

Type

Edit on GitHub

On this page