webdevpuneet.com

Radial Bar Chart — Circular Bar Chart HTML CSS JS

Radial Bar Chart · Charts · Plain HTML, CSS & JS · Live preview

CategoryCharts

Copy & paste

Source Code

<div class="rbc-card">
  <div class="rbc-head"><h3>Goal completion</h3></div>
  <div class="rbc-body">
    <svg class="rbc-svg" id="rbcSvg" viewBox="0 0 200 200" role="img" aria-label="Radial bar chart"></svg>
    <ul class="rbc-legend" id="rbcLegend"></ul>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Concentric ring layout
Each category is a ring at a decreasing radius with a faint full-circle track.
Arc length encodes value
stroke-dasharray = circumference and a computed dashoffset reveal the value fraction.
Per-ring circumference
Each ring uses its own 2 pi r, so arcs are correct at every radius.
Starts at the top
Rings are rotated -90deg so arcs begin at twelve o'clock, as expected for progress.
Round-capped arcs
Round line caps give the soft fitness-ring look.
Animated fill
Arcs sweep from empty to their value via a requestAnimationFrame-triggered transition.
Legend with percentages
Lists each category with its colour and value.
Data-driven & no library
Renders from a DATA array in plain HTML/CSS/SVG/JS — zero dependencies.

About this UI Snippet

Radial Bar Chart — Concentric Ring Arcs That Encode Value as Arc Length

Screenshot of the Radial Bar Chart snippet rendered live

A radial bar chart (or circular bar chart / progress rings) wraps each category into a concentric ring, with the arc length around the ring encoding its value — the look popularised by fitness trackers and dashboard progress widgets. This snippet builds it in plain HTML, CSS, SVG, and vanilla JavaScript, with animated arcs and a legend — no charting library.

Each category is a ring

Categories are drawn as concentric circles at decreasing radii (outer ring first), each a fixed thickness with a small gap between them. For every ring there is a faint full-circle track and a coloured value arc on top. Laying categories out as nested rings (rather than wedges like a pie or polar chart) is what defines a radial bar chart, and it reads naturally as a set of progress dials stacked into one compact graphic.

Arc length via stroke-dashoffset

The value arc is a stroked circle whose stroke-dasharray equals its full circumference (2πr), so the whole stroke is one dash exactly as long as the ring. Setting stroke-dashoffset to circumference × (1 − value/100) reveals just the fraction of the ring corresponding to the value — 86% fills 86% of the circle. This dash-offset technique is the standard, dependency-free way to draw any circular progress arc, applied here per ring with each ring's own circumference (since radius, and therefore circumference, differs per ring).

Starting at the top, with round caps

Each ring is rotated −90° around the centre so its arc begins at twelve o'clock, the orientation people expect for progress. Round line caps give the arcs the soft, pill-ended look of fitness rings. Because each arc is its own SVG circle, rings animate and can be styled independently.

Animated fill

The arcs start empty (offset at full circumference) and animate to their values on the next animation frame via a CSS transition on stroke-dashoffset — the requestAnimationFrame defer that lets the transition run from the start state. Each ring sweeps to its value, giving the satisfying "rings filling" reveal.

Legend and data-driven

A legend lists each category with its colour and percentage. Everything renders from a DATA array of { name, value, color } (values 0–100), so swapping in your metrics — goal completion, KPI attainment, capacity used — updates the rings and legend together. It is a clear reference for concentric ring layout and per-ring dash-offset arcs that power radial bar and progress-ring charts. Keep in mind that nesting more than four or five rings starts to hurt readability: each successive ring is both thinner in absolute terms relative to its smaller circumference and physically harder to compare to the others at a glance, so beyond that count a small multiples layout of separate single-ring gauges usually communicates the same data more clearly than one crowded radial stack.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA radial bar chart renders with four concentric rings that animate to their values.
  2. 2
    Read the ringsEach ring's coloured arc length is its value as a percentage; the legend lists the figures.
  3. 3
    Swap in your dataReplace the DATA array with your own { name, value, color } items (values 0-100).
  4. 4
    Adjust the ringsChange R0, THICK, and GAP to size and space the rings.
  5. 5
    Restyle itEdit the colours, track colour, or cap style to match your design.
  6. 6
    Wire to an APIMap your metrics into the DATA shape and call render().

Real-world uses

Common Use Cases

Daily fitness and habit goals
Show goal completion as concentric rings, with each arc length set by stroke-dasharray and a computed dashoffset. See activity rings for a themed take on the same idea.
KPI attainment dashboards
Display percent-to-target per metric, with each ring using its own 2πr circumference so arcs stay correct at every radius.
Capacity and usage views
Visualise quota or resource usage as rings on faint tracks, beside a quota usage meter for the exact figures.
Survey and score breakdowns
Compare several percentages in a compact visual. Arcs start at twelve o'clock because the rings are rotated −90°, as people expect from progress rings.
Onboarding completion widgets
Show several completion measures at once, such as profile, billing and team setup, in one small widget instead of three separate progress bars.
Related: Step Line Chart
See the Step Line Chart for a related charts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Each value arc is a stroked SVG circle with stroke-dasharray equal to its circumference (2 pi r), making the stroke one dash as long as the ring. Setting stroke-dashoffset to circumference × (1 − value/100) hides that fraction of the stroke, leaving the value's portion visible — so 86% reveals 86% of the ring. Each ring computes its own circumference because radius differs per ring.

A pie or polar-area chart divides one circle into angular wedges. A radial bar chart instead stacks each category as its own concentric ring, encoding value by how far the arc travels around that ring (arc length), not by wedge angle. It reads as a set of progress dials and is ideal for comparing several percentages or goal-completion metrics.

SVG circle strokes start at the 3 o'clock position by default. Rotating the arc -90 degrees around the centre moves the start to 12 o'clock, which is the orientation people expect for progress indicators (filling clockwise from the top). The rotation is applied per arc around the chart's centre point.

Add or remove entries in the DATA array for more or fewer rings. Adjust R0 (outer radius), THICK (ring thickness), and GAP (spacing) so the innermost ring still has a positive radius — roughly R0 minus (count − 1) × (THICK + GAP) should stay comfortably above zero. The arc math adapts to each ring's radius automatically.

In React, hold the data in useState and render rings from .map(), setting the dashoffset in a useEffect so the arcs animate after mount; in Vue, use v-for with onMounted; in Angular, *ngFor with ngAfterViewInit. The circumference and dashoffset math is framework-agnostic — only the state and the deferred offset-set move into the framework.