1001Ferramentas
๐ŸฉGenerators

SVG Progress Ring

Gera ring de progresso SVG (0-100).

SVG

โ€”

SVG progress rings: circular indicators for determinate progress

A progress ring (also called circular progress, radial bar or donut progress) is the circular cousin of the linear progress bar. Instead of filling a rectangle from left to right, it fills the perimeter of a circle clockwise from the top. It is the right pattern when progress is determinate โ€” you know the percentage โ€” and the surrounding UI benefits from a compact, badge-like shape: file upload widgets, dashboard KPIs, music players, Apple Watch activity rings. The SVG implementation is a single <circle> whose stroke-dasharray equals the full circumference and whose stroke-dashoffset hides the unfilled portion.

The math: circumference, dasharray, dashoffset

For radius r, the circumference is C = 2 * ฯ€ * r. With r = 45 the circumference is โ‰ˆ 282.74. Set stroke-dasharray to that circumference (so the dash pattern lasts the full perimeter) and animate stroke-dashoffset from C (empty) down to 0 (full). The offset for any percentage is C * (1 - percent / 100). Apply transform: rotate(-90deg) so the fill starts from twelve o'clock instead of three:

const circle = document.querySelector('.progress');
const C = 2 * Math.PI * 45;
circle.style.strokeDasharray = C;
circle.style.strokeDashoffset = C * (1 - percent / 100);

Smoothing, gradients and centre label

A bare ring jumps abruptly when the percent updates. Add transition: stroke-dashoffset 0.5s ease-out on the stroke and the browser interpolates between values for free. For the colour, brand-primary works for "in progress", but a sentiment palette helps: green for success / above-target, yellow for warning, red for over limit. Gradient strokes are supported via stroke="url(#gradient)" referencing a <linearGradient> in <defs>. For the percentage label in the centre, use a child <text x="50" y="50" text-anchor="middle" dominant-baseline="central"> or absolutely-positioned HTML overlaid on the SVG (HTML wins if you need rich typography or icons).

Use cases and inspirations

  • File upload โ€” percentage filled as bytes transfer (Google Drive, Dropbox).
  • Dashboard KPI โ€” "goal completion 73%" on analytics tools like Mixpanel or Amplitude.
  • Music player โ€” track elapsed time, YouTube and Spotify both use radial progress on miniplayer.
  • Achievement โ€” XP toward next level, Duolingo daily goals, Strava monthly distance.
  • Apple HealthKit rings โ€” three concentric overlapping rings for move, exercise and stand, a signature design pattern since watchOS 1.

Accessibility, SVG vs Canvas, libraries

Expose role="progressbar", aria-valuenow, aria-valuemin="0" and aria-valuemax="100" on the SVG root. Screen readers will announce "65 percent loaded". SVG is more accessible than Canvas (each node is a DOM element and styleable individually) and scales without rasterisation; Canvas wins only when you need to draw thousands of rings simultaneously. For prebuilt solutions try ProgressBar.js by Kimmo Brunfeldt, react-progressbar.js, or vue-circular-progress.

FAQ

What if the percentage goes above 100? A small overshoot reads visually as "exceeded the goal" โ€” clamp at 100 only if the design treats over-target as just "done". Apple's activity rings overshoot intentionally and start a second turn.

SVG or Canvas? SVG for one or a handful of rings (accessible, scalable, CSS-styleable). Canvas only when you have hundreds or thousands of indicators in a single view.

How do I show multiple stacked rings? Concentric <circle> elements with decreasing radii and different colours, each with its own dashoffset. Apple's activity ring uses exactly that approach.

Can I animate the fill? Yes โ€” animate stroke-dashoffset with CSS transition or the Web Animations API. Avoid animating the radius itself, which triggers reflow.

Related Tools