Skip to main content

ProgressRing

Every example on this page is live, drawn by the library's Storybook, where you can also change its props and see the result.

A ring that fills clockwise from twelve o'clock to show a percentage, with the percentage in its middle. Adapts to dark mode.

Size it in CSS (size="100%", or size="fill" for the room its flex parent leaves) rather than in pixels worked out from your layout: the ring stays round, its stroke and text scale with it, and it shrinks with its box in a saved render. A label names what it measures under the percentage, so the ring and its name are one block.

Import​

import { ProgressRing } from "~lib/data-display/progress-ring";

Props​

NameTypeRequiredDefaultDescription
percentagenumberYesN/AProgress (0-100), clamped
sizenumber | string | "fill"No100Width in pixels, any CSS width such as "100%", or "fill"; always round
strokeWidthnumberNo8Ring thickness in px, or in hundredths of the ring's width with a CSS size
showLabelbooleanNotrueShow the percentage
labelstringNoN/AWhat the ring measures, such as "of the year", set smaller under the percentage

Examples​

50%​

Open Half in Storybook

100%​

Open Full in Storybook

Custom Size​

Open Three Quarters in Storybook

No Percentage​

Open No Label in Storybook

With a Label​

Set label to name what the ring measures. It sits under the percentage, smaller, and the two are centered on the ring together. It is set at a share of the ring, and smaller still when a long label would run into the ring, so keep it to a word or two. With showLabel={false} the label sits alone in the middle.

Open With Label in Storybook

Sized to Its Box​

A pixel size stays that many pixels, so a ring whose size you worked out from the layout keeps them in a saved render laid out again in a smaller box. Give it a CSS width instead: the ring is drawn at its default size and scaled to its box, stroke and text together, so it keeps its proportions at any size and strokeWidth is in hundredths of its width:

Open Css Size in Storybook

size="fill" lets the ring take the room its flex parent leaves. Down a column it grows to the column's width and is the first thing to give way when the column runs short, so the text around it always fits; across a row it takes the row's height, which the row needs of its own. The ring is the shorter side of that room either way, centered:

Open Fill in Storybook
<div className="flex min-h-0 flex-1 flex-col gap-2">
<Heading level={4}>Spring term</Heading>
<ProgressRing percentage={share} size="fill" label="of the term" />
</div>

See Also​