Radial Bar Chart

Pro

Concentric progress rings, one per track, with per-track scales, a configurable sweep and start angle, a centre readout and a legend. States under the plot what concentric arcs cannot be read for, and marks any track past the end of its scale. Pure SVG.

</>sv-radial-bar-chart chartradialprogressgaugerings
import { SvRadialBarChartComponent } from '@styloviz-pro/charts';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Centre readout

Pro

Dial sweep

Pro

Track interactions

Pro

React to a track running past its scale

Pro

When to use

  • A handful of progress-toward-capacity figures that share a scale — utilisation, quota, completion.
  • A compact card where a row of bars would not fit.
  • For one value against banded thresholds, use the Gauge; for part-to-whole, a Donut.

Async states

  • loading
  • empty
  • error
  • retry

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the tracks are being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
emptyMessagestring'No data to plot'Copy for the no-data state.
filteredbooleanfalseTrue when the emptiness is caused by a filter rather than an empty set.
tracksreadonly RadialBarTrack[][]Concentric tracks, outermost first.
maxnumber100Chart-wide scale maximum; a per-track `max` still wins.
sizenumber260Overall diameter in pixels.
thicknessnumber14Ring thickness in pixels.
gapnumber8Gap between rings in pixels.
startAnglenumber0Where the rings start, in degrees clockwise from twelve o'clock.
sweepnumber360How far a full-value ring sweeps, in degrees. `360` is a closed ring; `270` leaves a gap at the bottom, which is where a dial normally puts its scale.
roundedbooleantrueRound the leading edge of each arc.
showLegendbooleantrueShow the legend (swatch, label, value and share) under the rings. When off, each track's share is still printed as one plain line: arc length cannot be compared across rings, so the share is never optional.
centerValuestring''Large text in the middle of the rings (e.g. a headline figure).
centerLabelstring''Caption under `centerValue`.
animatedbooleantrueAnimate arcs on value change.
titlestring''Chart title, rendered above the plot.
ariaLabelstring''Accessible name override. Falls back to a generated summary.
customClassstring''Extra CSS classes applied to the root wrapper.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
trackHoverRadialBarTrackEventEmitted when a track is hovered or keyboard-focused.
trackSelectRadialBarTrackEventEmitted when a track is clicked or activated with Enter/Space.

Wire it to your API

This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.

Template

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `tracks`, `loading` and `error`.
  • Set `filtered` when a search or filter is active. It is the difference between "you have no orders" and "no orders match this filter" — telling a customer with 4,000 orders the first one reads as a bug.
  • Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.

Full walkthrough: Connecting to a backend.

Customization & theming

  • Ring thickness, gap and diameter.
  • Start angle and sweep (360° ring or a 270° dial).
  • Per-track scale and colour, rounded or butt caps.
  • Legend and centre readout each optional.
  • A track past its maximum draws a full ring with a dashed rim outside it and reports its real percentage; one with a non-finite or negative value leaves its ring empty rather than drawing a zero nobody measured.

Best practices

  • Do: Keep it to four or five rings — an inner ring is shorter for the same percentage and reads as smaller.
  • Do: Put the headline figure in `centerValue` rather than making the reader add up rings.
  • Don't: Do not use it for part-to-whole; the rings are independent scales, not slices.
  • Don't: Do not compare two rings by eye and conclude one is larger. Concentric rings have different circumferences, so the same percentage draws a visibly shorter arc on an inner track than on an outer one — the eye compares arc LENGTH, and arc length is not the value. The chart says so under the plot and prints each track's share — in the legend, or on a plain line under the rings when `showLegend` is off; those are the comparable figures.
  • Do: Give every track the same maximum unless you have a reason not to. Mixed maxima are supported and disclosed, but two arcs of equal length standing for entirely different numbers is the worst reading this chart can produce.
  • Do: Send a value past its maximum rather than clamping it yourself. A ring has nowhere to go past a full revolution, so the chart draws it full and adds a dashed rim, reports the real percentage, and names the track in the note. Clamping upstream throws that away and leaves 150 of 100 looking exactly like 100 of 100.
  • Tip: Angles are degrees clockwise from twelve o’clock, shared with `sv-gauge-chart`.

Accessibility

  • Each ring’s track is a `role="button"` focus target named with its value, scale and percentage — a 0 % track stays reachable because the focus target is the track, not the value arc.
  • An inner ring is physically shorter than an outer one at the same percentage, so arc length cannot be compared by eye at all — the encoding misleads even a sighted reader. `sv-data-summary-table` publishes each track's value, share and, on per-track scales, its scale maximum: the pair of numbers the rings themselves cannot convey.
  • The caveat that arc lengths are not comparable is stated in the rendered output, not only in the table — the reader being misled by unequal baselines is the one looking straight at the rings. It names the differing scale maxima when the tracks disagree, and each over-scale track with how far over it is. There is no input to hide it, on the same rule as the bullet chart's scale note.
  • An over-scale track says so in its accessible name as well as with the dashed rim, because a rim has nothing to say to a screen reader; a track with no usable value is named as such rather than announced as zero — "no value" in the chart's name, "No value" in the table's Share cell and the legend, and `value: null` / `percent: null` on the emitted event.
  • Animation is disabled under `prefers-reduced-motion`.

Feedback on Radial Bar Chart

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.