Radial Chart
Concentric radial bars - one ring per data row with sweep proportional to value.
Overview
RadialChart is a recharts chart built on the shadcn chart primitive (ChartContainer) for concentric polar bars. Each data row produces one bar around the chart center; each bar sweeps proportionally to its dataKey value. Bar colors come from each row's fill (e.g. fill: "var(--chart-1)"), and an optional config supplies the labels shown in the tooltip.
Reach for RadialChart when you want a compact, decorative ranking of three to five items - top categories, leading drivers, ranked metrics in a hero card. For exact comparison BarChart reads faster; for share-of-whole at a glance PieChart is more familiar.
The React edition (@gremorie/rx-data) renders with recharts inside the shadcn chart primitive; the Angular edition (@gremorie/ng-data) renders headless d3 geometry inside a styled SVG. The rendering engine differs; the public surface is identical input-for-input.
Anatomy
<radial-chart>
└─ figure (role="img") card surface, aspect-square
├─ svg
│ └─ concentric bars, one per row
│ └─ row fill colored (palette / per-row fill)
├─ tooltip overlay (optional via tooltip)
├─ legend
└─ sr-only data tableThe React edition composes this surface through the shadcn chart primitive:
ChartContainer responsive square frame + tooltip label config
└─ RadialBarChart recharts polar plot area
├─ ChartTooltip hover card
│ └─ ChartTooltipContent themed tooltip body
├─ PolarGrid circular grid
└─ RadialBar one bar per row, with a faint background trackPreview
- Chrome
- Safari
- Firefox
- Edge
- Other
| browser | visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
'use client';import { RadialChart, type ChartConfig, type ChartDatum,} from '@gremorie/rx-data';// Categorical (pie / radial): one chart token per row via `fill`.const browserData: ChartDatum[] = [ { browser: 'Chrome', visitors: 275, fill: 'var(--chart-1)' }, { browser: 'Safari', visitors: 200, fill: 'var(--chart-2)' }, { browser: 'Firefox', visitors: 187, fill: 'var(--chart-3)' }, { browser: 'Edge', visitors: 173, fill: 'var(--chart-4)' }, { browser: 'Other', visitors: 90, fill: 'var(--chart-5)' },];const browserConfig: ChartConfig = { visitors: { label: 'Visitors' }, Chrome: { label: 'Chrome' }, Safari: { label: 'Safari' }, Firefox: { label: 'Firefox' }, Edge: { label: 'Edge' }, Other: { label: 'Other' },};export function RadialChartPreview() { return ( <RadialChart data={browserData} config={browserConfig} nameKey="browser" dataKey="visitors" /> );}Installation
bash npx gremorie@latest add rx-radial-chart bash pnpm dlx gremorie@latest add rx-radial-chart
bash yarn dlx gremorie@latest add rx-radial-chart
bash bunx --bun gremorie@latest add rx-radial-chart
Usage
import { RadialChart, type ChartConfig, type ChartDatum } from "@gremorie/rx-data";
const data: ChartDatum[] = [
{ category: "Chrome", visitors: 275, fill: "var(--chart-1)" },
{ category: "Safari", visitors: 200, fill: "var(--chart-2)" },
{ category: "Firefox", visitors: 187, fill: "var(--chart-3)" },
{ category: "Edge", visitors: 173, fill: "var(--chart-4)" },
];
const config: ChartConfig = {
visitors: { label: "Visitors" },
Chrome: { label: "Chrome" },
Safari: { label: "Safari" },
Firefox: { label: "Firefox" },
Edge: { label: "Edge" },
};
export function TopBrowsers() {
return (
<RadialChart data={data} config={config} nameKey="category" dataKey="visitors" />
);
}import { Component } from '@angular/core';
import { RadialChart } from '@gremorie/ng-data';
import type { ChartConfig, ChartDatum } from '@gremorie/ng-data';
@Component({
selector: 'app-top-browsers',
imports: [RadialChart],
template: ` <radial-chart [data]="data" [config]="config" nameKey="category" dataKey="visitors" />
`,
})
export class TopBrowsersComponent {
readonly data: ChartDatum[] = [
{ category: 'Chrome', visitors: 275, fill: 'var(--chart-1)' },
{ category: 'Safari', visitors: 200, fill: 'var(--chart-2)' },
{ category: 'Firefox', visitors: 187, fill: 'var(--chart-3)' },
{ category: 'Edge', visitors: 173, fill: 'var(--chart-4)' },
];
readonly config: ChartConfig = {
visitors: { label: 'Visitors' },
Chrome: { label: 'Chrome' },
Safari: { label: 'Safari' },
Firefox: { label: 'Firefox' },
Edge: { label: 'Edge' },
};
}
API
<RadialChart>
A recharts radial bar chart composed inside the shadcn chart primitive (ChartContainer). One concentric bar per row; bar colors come from each row's fill, and the optional config provides the labels shown in the tooltip.
| Prop | Type | Default | Description |
|---|---|---|---|
data | readonly ChartDatum[] | - | Tabular data. One row per bar. Each row needs a string field at nameKey, a numeric field at dataKey, and a fill for its bar color (e.g. var(--chart-1)). |
nameKey | string | - | Name of the category label field. Used to resolve the tooltip label. |
dataKey | string | - | Name of the numeric value field. The sweep of each bar is proportional to this value relative to the max across rows. |
config | ChartConfig | {} | Optional label/color map keyed by category name (and value key). Powers the tooltip labels. |
tooltip | boolean | true | Toggles the hover tooltip (ChartTooltip + ChartTooltipContent). |
className | string | - | Merged onto the ChartContainer. The bundled style supplies a centered, square aspect frame. |
Chart primitives for custom composition
For full control, compose raw recharts inside ChartContainer using the shadcn chart primitives, all re-exported from @gremorie/rx-data. This mirrors the official shadcn radial block (ui.shadcn.com/charts/radial).
| Export | Role |
|---|---|
ChartContainer | Responsive frame; injects per-key CSS color vars (--color-<key>) from config. |
ChartTooltip / ChartTooltipContent | Hover card and its themed content. |
ChartLegend / ChartLegendContent | Optional legend and its themed content. |
useChart | Hook returning the active config from context (use inside custom children). |
RadialBarChart, RadialBar, PolarGrid, Label | Raw recharts primitives composed inside ChartContainer. |
Types
| Type | Shape |
|---|---|
ChartDatum | Record<string, string | number> & { fill?: string } - one row of chart data; fill sets the per-bar color. |
ChartConfig | Map of key → { label?, icon?, color? }; provides tooltip/legend labels (and optional colors). |
Bar colors come from each row's fill (e.g. fill: "var(--chart-1)"), not
from config. The optional config maps each category name to a {label}
and drives the labels shown in the tooltip.
Composition
- Pick
nameKeyanddataKey- the label column and the numeric column. Both must exist on every row. - Set a
fillper row - point each row at a--chart-*token (e.g.fill: "var(--chart-1)"). This is where bar colors come from. - Add a
configmapping each category name (and the value key) to a{ label }so the tooltip reads cleanly. - Order rows by magnitude. The largest value sits on the outer bar; the smallest on the innermost. The decreasing radius reinforces ranking visually.
- Cap the row count at three to five. Six or more bars get visually noisy and lose the ranking signal.
The chart auto-sizes to its parent through ChartContainer (recharts ResponsiveContainer). The frame forces aspect-square so the bars stay circular.
Variations
Default ranking
- Chrome
- Safari
- Firefox
- Edge
- Other
| browser | visitors |
|---|---|
| Chrome | 275 |
| Safari | 200 |
| Firefox | 187 |
| Edge | 173 |
| Other | 90 |
'use client';import { RadialChart, type ChartConfig, type ChartDatum,} from '@gremorie/rx-data';// Categorical (pie / radial): one chart token per row via `fill`.const browserData: ChartDatum[] = [ { browser: 'Chrome', visitors: 275, fill: 'var(--chart-1)' }, { browser: 'Safari', visitors: 200, fill: 'var(--chart-2)' }, { browser: 'Firefox', visitors: 187, fill: 'var(--chart-3)' }, { browser: 'Edge', visitors: 173, fill: 'var(--chart-4)' }, { browser: 'Other', visitors: 90, fill: 'var(--chart-5)' },];const browserConfig: ChartConfig = { visitors: { label: 'Visitors' }, Chrome: { label: 'Chrome' }, Safari: { label: 'Safari' }, Firefox: { label: 'Firefox' }, Edge: { label: 'Edge' }, Other: { label: 'Other' },};export function RadialChartPreview() { return ( <RadialChart data={browserData} config={browserConfig} nameKey="browser" dataKey="visitors" /> );}<RadialChart
data={data}
config={config}
nameKey="category"
dataKey="visitors"
/><radial-chart
[data]="data"
[config]="config"
nameKey="category"
dataKey="visitors"
/>The default. Four bars provide a comfortable visual rhythm without crowding.
Top-three highlight
<RadialChart
data={topThree}
config={config}
nameKey="product"
dataKey="revenue"
className="max-w-xs"
/><radial-chart
class="max-w-xs"
[data]="topThree"
[config]="config"
nameKey="product"
dataKey="revenue"
/>For top-three callouts in a hero card. Constrain the surface width so the bars stay readable in a tight column.
No tooltip
Set tooltip to false for a static, decorative ranking - useful when the bars are labeled elsewhere or the chart is a glanceable hero element rather than an explorable surface.
<RadialChart
data={data}
config={config}
nameKey="category"
dataKey="visitors"
tooltip={false}
/><radial-chart
[data]="data"
[config]="config"
nameKey="category"
dataKey="visitors"
[tooltip]="false"
/>Custom composition
When you need a different track treatment, gradient fills, a center label, or a legend, compose raw recharts inside ChartContainer. This mirrors the official shadcn radial block.
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
type ChartDatum,
} from '@gremorie/rx-data';
import { PolarGrid, RadialBar, RadialBarChart } from 'recharts';
export function ExplicitColorRadial({
data,
config,
nameKey,
dataKey,
}: {
data: ChartDatum[];
config: ChartConfig;
nameKey: string;
dataKey: string;
}) {
return (
<ChartContainer
config={config}
className="mx-auto aspect-square max-h-[260px]"
>
<RadialBarChart data={data} innerRadius={30} outerRadius={110}>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent nameKey={nameKey} hideLabel />}
/>
<PolarGrid gridType="circle" />
<RadialBar dataKey={dataKey} background />
</RadialBarChart>
</ChartContainer>
);
}Bar colors come from each row's fill; adjust innerRadius / outerRadius or swap the PolarGrid treatment for a different look.
Accessibility
- Accessibility layer: recharts'
accessibilityLayerprovides keyboard navigation and screen-reader announcements for the chart data. - Token contrast:
--chart-1through--chart-5ship with WCAG AA contrast against the card background in both light and dark themes. - Track contrast: the faint background track behind each bar (recharts
background) defines the ring without competing with the fill. - Limit bar count: more than five bars becomes hard to scan. Reach for
BarChartwhen more rows are needed.
Related
- PieChart - sibling polar layout for share-of-whole rather than ranking.
- BarChart - reach for bars when you have more than five items or need exact comparison.
- RadarChart - sibling polar layout for multi-axis profile comparison.