Loaders & Progress

Circular Progress

A ring that fills to a value and eases into every change.

Circular Progress draws a track and an indicator on an SVG circle, then animates the indicator's stroke-dashoffset from empty to the current value. Because the ring is one path rather than a clipped rectangle, it follows any diameter and thickness without extra layout.

Changing value animates from wherever the ring currently sits, so a stream of updates reads as a smooth climb rather than a series of jumps. The ring holds at its final value when the visitor has asked for reduced motion.

Usage

72%Storage
45%Memory
91%CPU
<script setup lang="ts">
const rings = [
  { value: 72, size: 132, caption: 'Storage' },
  { value: 45, size: 108, caption: 'Memory' },
  { value: 91, size: 84, caption: 'CPU' },
]
</script>

<template>
  <div class="flex w-full flex-wrap items-center justify-center gap-8 py-6">
    <MCircularProgress
      v-for="ring in rings"
      :key="ring.caption"
      :value="ring.value"
      :size="ring.size"
      :caption="ring.caption"
    />
  </div>
</template>

Examples

Customize

68%Storage

Customize

CaptionStorage
Duration1.1
Label
Show Label
Size140
Stroke Width10
Value68

Props

Prop Type Default Description
valuenumber0Progress from 0 to 100. Values outside that range are clamped.
sizenumber140Diameter of the ring, in pixels. The stroke is drawn inside this box.
strokeWidthnumber10Thickness of the ring, in pixels.
durationnumber1.1Seconds the ring takes to reach a new value.
showLabelbooleantrueDraw the percentage in the middle of the ring. Turn it off when the ring is decoration.
captionstringundefinedText under the percentage, for a short label like Storage.
labelstringundefinedAccessible description of the ring. Defaults to the current percentage.
classstring''CSS classes for the wrapper.

Slots

Slot Props Description
default-Replaces the percentage and caption in the middle of the ring.

UI

This component's theme exposes the slots below. Override any of them per instance with the ui prop, or app-wide under ui.circularProgress in app.config.ts.

Prop Type Default Description
uiobject-Per-slot classes merged over the theme defaults.
Slot Props Description
root-relative inline-flex items-center justify-center
svg--rotate-90
track-stroke-current text-muted/20
indicator-stroke-current text-primary
label-absolute inset-0 flex flex-col items-center justify-center text-highlighted
value-text-lg font-semibold tabular-nums
caption-text-xs text-muted

Accessibility

The ring is a role="img" with a label that spells out the value, so a screen reader hears "72% complete" instead of nothing. The digits in the middle are inside that labelled image and stay legible without a second announcement. Because the value is also readable as text, the ring never has to carry the number on its own.

Copyright © 2026