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
Handwriting Generator
Convert typed text into an image with handwriting appearance. Useful for adding a personal touch to digital work.
Resume Generator
Fill a simple printable A4 CV from a form with personal data, education and experience.
Favicon Generator
Generate a favicon from text/emoji in all common sizes (16, 32, 48, 64, 192, 512). PNG download.