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.

html
<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

required

data 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

required

categoryKey sets which field on each row labels the bar.

  • Organic
  • Direct
  • Referral
  • Paid

Value key

required

valueKey sets which field holds its numeric value.

  • Organic
  • Direct
  • Referral
  • Paid

ARIA label

required

ariaLabel 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 search brings in more signups than direct and referral combined.
  • 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.

No data to display

API Reference

Generated from the component's source — props, slots and emits as the component actually declares them.

Props

Prop
Type
Default
Description
datarequired
Record<string, unknown>[]
One object per bar. Worth knowing before reaching for this chart: bending a bar around a circle 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 close values, a plain `UiBarChart` is the honest choice.
categoryKeyrequired
string
Field holding each bar's label.
valueKeyrequired
string
Field holding each bar's numeric value.
ariaLabelrequired
string
What the chart shows, for screen readers. Required.
string
A longer accessible description, for detail the label shouldn't carry.
"rose" | "concentric"
'rose'
Which way the bars grow. - `rose` — outward from the centre, one angular slot each. Every bar shares a baseline, so this is the more comparable of the two. - `concentric` — around the circle, one ring each. The activity-rings look, at the cost of each ring having a different circumference.
number
Upper bound of the value scale. Defaults to the largest value.
number
0.3
Where the bars start, as a fraction of the radius.
number
6
Corner radius on each bar, in pixels.
ChartColorName[]
Per-bar colors, positionally matched to `data`.
(value: number) => string
Formats values in the tooltip and legend.
boolean
true
Shows the tooltip on hover.
boolean
true
Shows the legend. These bars have no axis labels, so it carries their names.
"top" | "bottom"
'bottom'
Where the legend sits relative to the plot.
"start" | "center" | "end"
'center'
Horizontal placement of the legend.
"horizontal" | "vertical"
'horizontal'
How the legend entries flow.
number
320
Height of the plot in pixels. Ignored when `aspectRatio` is set.
number
Width-to-height ratio, sizing the chart from its container's width.
boolean
false
Replaces the plot with a skeleton of the same height.

Emits

Event
Payload
Description
focusChange
[label: string | null]
The bar under the pointer, or `null` once it leaves.

Types

ts
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;
}
ts
type ChartColorName = ChartColorFamily | `${ChartColorFamily}-${ChartColorShade}`;