RadialBarChart
Bars bent around a circle — a rose growing outward from a shared centre, or concentric activity rings. A compact summary; bending a bar makes its length depend on its radius, so a plain `BarChart` is the honest choice for close ranking.
<UiRadialBarChart :data="..." :categoryKey="..." :valueKey="..." :ariaLabel="..." />Needs the charts module
This component ships in @jgastager/bundy-ui/charts, a separate module so projects that never draw a chart don't carry the paint classes these need. Nothing extra to install — just add the module entry. See Charts.
Data
requireddata is one object per bar. Worth knowing before reaching for this chart: bending a bar around a circle makes the outer ones longer for the same value, so it reads as a ranking rather than an exact comparison. A BarChart is the honest choice when the numbers have to be compared precisely.
- Organic · 1,840
- Direct · 1,210
- Referral · 760
- Paid · 520
Bending a bar makes its length depend on its radius, so the same value looks longer further out. It reads well as a compact summary; when the reader has to rank values that are close together, the same data in a horizontal BarChart is simply more accurate.
Hovering dims every slice except the focused one to 0.7 rather than drawing a ring on it — a ring is a dot, which reads as a stray mark sitting on the arc. The hit test is polar: the angle and distance under the pointer, not a bounding box.
The hover fade is a CSS transition over the library's own 250ms duration, so it costs nothing and honours prefers-reduced-motion. There's no animate prop and nothing tweens on a data change — the marks are plain SVG elements Vue patches directly.
Category key
requiredcategoryKey sets which field on each row labels the bar.
- Organic
- Direct
- Referral
- Paid
Value key
requiredvalueKey sets which field holds its numeric value.
- Organic
- Direct
- Referral
- Paid
ARIA label
requiredariaLabel is required. These bars carry no axis, so it's doing more work here than on a cartesian chart.
- Organic
- Direct
- Referral
- Paid
ARIA description
ariaDescription is the detail the label shouldn't carry.
- Organic
- Direct
- Referral
- Paid
Variant
variant decides how the bars are arranged. rose grows them outward from the centre, one angular slot each — every bar shares a start, so length is the comparison. concentric wraps each bar around its own ring instead, which is the shape for a set of independent progress readings.
- Organic · 1,840
- Direct · 1,210
- Referral · 760
- Paid · 520
- Revenue · 82%
- Retention · 64%
- Activation · 47%
rose gives every bar a shared starting radius, which makes it the more comparable of the two variants. concentric gives each one its own ring — and its own circumference, so equal values trace different arc lengths.
Max
max is the upper bound of the value scale, defaulting to the largest value present. Pin it when the bars are shares of a known whole — otherwise the biggest one always fills the ring, whatever it is.
- Revenue · 82%
- Retention · 64%
- Activation · 47%
- Revenue · 82%
- Retention · 64%
- Activation · 47%
Set max to a shared target for concentric; "how close to done" is the one comparison those rings do support.
Inner radius
innerRadius sets where the bars start, as a fraction of the radius. A bigger hole leaves room for a headline number in the middle.
Radius
radius rounds the end of each bar. It's mostly a matter of taste, but a rounded end reads as a progress indicator where a square one reads as a measurement.
Colors
colors pins a paint per bar, matched positionally to data.
- Revenue · 82%
- Retention · 64%
- Activation · 47%
Colors are the library's own semantic ones — primary, secondary, success, warning, error, info, pending, neutral — and any shade of them, primary-400 through primary-950, exactly as the bg-* utilities spell them. Set color per series (or per item) to pin one; leave it unset to take the next slot of the default sequence. neutral and secondary are never handed out automatically, so an unlabelled series never lands on them.
Value format
valueFormat formats the values in the tooltip and legend.
- Organic · 1,840
- Direct · 1,210
- Referral · 760
- Paid · 520
Tooltip
tooltip shows the tooltip on hover.
- Organic
- Direct
- Referral
- Paid
Legend
legend is on by default and worth keeping — these bars have no axis labels, so it's what carries their names.
The legend is on by default because concentric rings have no axis labels at all, and rose slots only get their names from the legend.
Legend position
legendPosition sets where the legend sits relative to the plot.
- Organic
- Direct
- Referral
- Paid
Legend align
legendAlign places the key horizontally. Centre suits the circular plot above it.
- Revenue
- Retention
- Activation
- Revenue
- Retention
- Activation
- Revenue
- Retention
- Activation
Legend orientation
legendOrientation flows the entries in a row or a column. vertical gives each bar its own line.
- Organic · 1,840
- Direct · 1,210
- Referral · 760
- Paid · 520
Height
height is the plot's height in pixels; the rings are sized to fit inside it. It's ignored once aspectRatio is set.
- Revenue
- Retention
- Activation
- Revenue
- Retention
- Activation
Aspect ratio
aspectRatio sizes the chart from its container's width instead of a fixed height.
- Organic
- Direct
- Referral
- Paid
Loading
loading is a skeleton at the chart's exact height; an empty data array gets the empty state instead.
API Reference
Generated from the component's source — props, slots and emits as the component actually declares them.
Props
datarequiredRecord<string, unknown>[]"rose" | "concentric"'rose'Emits
focusChange[label: string | null]Types
interface ChartPlot {
x: number;
y: number;
width: number;
height: number;
/** Right edge, since marks need it more often than the width. */
right: number;
/** Bottom edge, which is also the x axis' baseline. */
bottom: number;
}type ChartColorName = ChartColorFamily | `${ChartColorFamily}-${ChartColorShade}`;