Skip to content

cv-progress-ring

A read-only circular indicator that communicates determinate or indeterminate loading/completion progress via an SVG ring.

Headless: createProgress

Usage

View source
html
<div class="progress-ring-demo-shell" data-demo="progress-ring" data-live-demo-height="680">
  <section class="progress-ring-demo-hero" aria-labelledby="progress-ring-demo-title">
    <div class="progress-ring-demo-copy">
      <span class="progress-ring-demo-kicker">cv-progress-ring</span>
      <h3 id="progress-ring-demo-title">Compact progress for auditable operations.</h3>
      <p>
        Use the ring when the surrounding surface already explains the operation and the UI needs a precise,
        read-only status signal: determinate percentage, custom range, complete state, or indeterminate work.
      </p>
    </div>

    <div class="progress-ring-demo-stage" aria-label="Vault sync progress summary">
      <div class="progress-ring-demo-stage-ring">
        <cv-progress-ring
          class="progress-ring-demo-ring progress-ring-demo-ring--hero"
          value="72"
          value-text="72 percent synced"
          aria-label="Vault sync progress"
          >72%</cv-progress-ring
        >
        <span class="progress-ring-demo-stage-label">Vault sync</span>
      </div>

      <dl class="progress-ring-demo-telemetry">
        <div>
          <dt>Value</dt>
          <dd>72 / 100</dd>
        </div>
        <div>
          <dt>Contract</dt>
          <dd><code>role="progressbar"</code></dd>
        </div>
        <div>
          <dt>Source</dt>
          <dd>headless state</dd>
        </div>
      </dl>
    </div>
  </section>

  <section class="progress-ring-demo-states" aria-label="Progress ring states">
    <article class="progress-ring-demo-state">
      <cv-progress-ring
        class="progress-ring-demo-ring progress-ring-demo-ring--state"
        value="34"
        value-text="34 percent indexed"
        aria-label="Indexing progress"
        >34%</cv-progress-ring
      >
      <div>
        <strong>Determinate</strong>
        <span><code>value</code>, <code>min</code>, and <code>max</code> drive percentage and ARIA.</span>
      </div>
    </article>

    <article class="progress-ring-demo-state">
      <cv-progress-ring
        class="progress-ring-demo-ring progress-ring-demo-ring--range"
        value="6"
        min="0"
        max="8"
        value-text="6 of 8 shards sealed"
        aria-label="Shard sealing progress"
        >6/8</cv-progress-ring
      >
      <div>
        <strong>Custom range</strong>
        <span>Non-percentage work can keep the visible label and assistive text aligned.</span>
      </div>
    </article>

    <article class="progress-ring-demo-state">
      <cv-progress-ring
        class="progress-ring-demo-ring progress-ring-demo-ring--complete"
        value="100"
        aria-label="Verification complete"
        >OK</cv-progress-ring
      >
      <div>
        <strong>Complete</strong>
        <span><code>data-complete</code> switches the indicator to the success token.</span>
      </div>
    </article>

    <article class="progress-ring-demo-state">
      <cv-progress-ring
        class="progress-ring-demo-ring progress-ring-demo-ring--state"
        indeterminate
        aria-label="Checking transport"
      ></cv-progress-ring>
      <div>
        <strong>Indeterminate</strong>
        <span>Use while progress is real but the current value is not measurable.</span>
      </div>
    </article>
  </section>
</div>

Anatomy

<cv-progress-ring> (host)
└── <div part="base" role="progressbar">
    └── <svg part="svg" viewBox="0 0 100 100">
    │   ├── <circle part="track">
    │   └── <circle part="indicator">
    └── <span part="label">
        └── <slot>

Attributes

AttributeTypeDefaultDescription
valueNumber0Current progress value; clamped to [min, max]
minNumber0Minimum boundary
maxNumber100Maximum boundary
indeterminateBooleanfalseSwitches to indeterminate (spinning animation) mode
value-textStringStatic override for aria-valuetext; takes precedence over the percentage fallback
aria-labelStringAccessible label passed through to headless

Slots

SlotDescription
(default)Label content rendered inside the ring (e.g. percentage text)

CSS Parts

PartElementDescription
base<div>Outer container with role="progressbar"
svg<svg>SVG element containing track and indicator circles
track<circle>Background circle representing the full track
indicator<circle>Foreground arc representing current progress
label<span>Content overlay centered inside the ring; wraps the default slot

CSS Custom Properties

PropertyDefaultDescription
--cv-progress-ring-size80pxDiameter of the ring (sets both inline-size and block-size)
--cv-progress-ring-track-width4pxStroke width of the background track circle
--cv-progress-ring-indicator-width4pxStroke width of the progress indicator arc
--cv-progress-ring-track-colorvar(--cv-color-surface, #141923)Background color of the track circle stroke
--cv-progress-ring-indicator-colorvar(--cv-color-primary, #65d7ff)Color of the filled indicator arc stroke
--cv-progress-ring-label-colorvar(--cv-color-text, #e8ecf6)Text color for the label slot content

Visual States

Host selectorDescription
:host([indeterminate])Spinning/rotating animation on the indicator arc; indicator has a fixed arc length
:host([data-complete])Success appearance when value >= max (indicator stroke uses --cv-color-success)

Reactive State Mapping

cv-progress-ring is a visual adapter over headless createProgress.

UIKit PropertyDirectionHeadless Binding
valueattr -> actionactions.setValue(value)
minattr -> optionPassed as min in createProgress(options)
maxattr -> optionPassed as max in createProgress(options)
indeterminateattr -> actionactions.setIndeterminate(value)
value-textattr -> optionPassed as valueText in createProgress(options)
aria-labelattr -> optionPassed as ariaLabel in createProgress(options)
Headless StateDirectionDOM Reflection
state.percentage()state -> styleSets stroke-dashoffset on the indicator <circle> to represent the filled arc
state.isIndeterminate()state -> attr[indeterminate] host attribute
state.isComplete()state -> attr[data-complete] host attribute
  • contracts.getProgressProps() is spread onto the inner [part="base"] element to apply role, aria-valuenow, aria-valuemin, aria-valuemax, aria-valuetext, aria-label, and id.
  • ARIA value attributes are present only in determinate mode; headless omits them in indeterminate mode.
  • aria-valuetext resolution order (determinate only): valueText static override > rounded percentage fallback.
  • UIKit does not own clamping, completion, or percentage logic; headless state is the source of truth.

Events

None. cv-progress-ring is a read-only indicator with no user-modifiable state.

ChromVoid UIKit documentation