Skip to content

cv-progress

A read-only indicator that communicates determinate or indeterminate loading/completion progress.

Headless: createProgress

Usage

View source
html
<div class="progress-demo-shell" data-demo="progress" data-live-demo-height="640">
  <section class="progress-demo-hero" aria-labelledby="progress-demo-title">
    <div class="progress-demo-copy">
      <span class="progress-demo-kicker">Linear operation state</span>
      <h3 id="progress-demo-title">Track a running job without turning it into an interaction.</h3>
      <p>
        Use <code>cv-progress</code> for read-only work: encrypted exports, verification passes, sync queues,
        and loading states. The component owns ARIA progress semantics while the workflow owns the value and
        tone.
      </p>
    </div>

    <dl class="progress-demo-metrics" aria-label="Progress contract summary">
      <div>
        <dt>Semantics</dt>
        <dd>role="progressbar"</dd>
      </div>
      <div>
        <dt>Value</dt>
        <dd>min / max / value</dd>
      </div>
      <div>
        <dt>Fallback</dt>
        <dd>indeterminate</dd>
      </div>
    </dl>
  </section>

  <section class="progress-demo-workbench" aria-labelledby="progress-demo-workbench-title">
    <div class="progress-demo-panel">
      <header class="progress-demo-panel-head">
        <div>
          <span class="progress-demo-kicker">Encrypted export</span>
          <h4 id="progress-demo-workbench-title">media-archive.cvault</h4>
        </div>
        <cv-badge variant="primary" pulse>Running</cv-badge>
      </header>

      <div class="progress-demo-primary-progress">
        <div class="progress-demo-progress-label">
          <span>Transfer window</span>
          <strong>1.8 GB / 2.4 GB</strong>
        </div>
        <cv-progress
          class="progress-demo-main-progress"
          tone="upload"
          value="74"
          value-text="74%"
          aria-label="Encrypted export transfer progress"
        >
          74%
        </cv-progress>
      </div>

      <div class="progress-demo-proof-grid" aria-label="Current transfer details">
        <div>
          <span>Range</span>
          <strong>0-100</strong>
        </div>
        <div>
          <span>Text</span>
          <strong>value-text="74%"</strong>
        </div>
        <div>
          <span>Tone</span>
          <strong>upload</strong>
        </div>
      </div>
    </div>

    <aside class="progress-demo-queue" aria-label="Export queue stages">
      <div class="progress-demo-step progress-demo-step--complete">
        <div>
          <span>Step 1</span>
          <strong>Encrypt chunks</strong>
        </div>
        <cv-progress tone="success" value="100" aria-label="Encrypt chunks complete"></cv-progress>
      </div>

      <div class="progress-demo-step progress-demo-step--active">
        <div>
          <span>Step 2</span>
          <strong>Upload sealed archive</strong>
        </div>
        <cv-progress tone="upload" value="74" aria-label="Upload sealed archive progress"></cv-progress>
      </div>

      <div class="progress-demo-step">
        <div>
          <span>Step 3</span>
          <strong>Verify remote manifest</strong>
        </div>
        <cv-progress tone="queued" value="16" aria-label="Verify remote manifest queued"></cv-progress>
      </div>
    </aside>
  </section>

  <section class="progress-demo-tones" aria-labelledby="progress-demo-tones-title">
    <div class="progress-demo-section-header">
      <span class="progress-demo-kicker">State palette</span>
      <h4 id="progress-demo-tones-title">Choose tone by operation state, not decoration.</h4>
    </div>

    <div class="progress-demo-tone-grid">
      <div class="progress-demo-tone">
        <span>Default</span>
        <cv-progress value="42" aria-label="Default determinate progress"></cv-progress>
      </div>
      <div class="progress-demo-tone">
        <span>Queued</span>
        <cv-progress tone="queued" value="28" aria-label="Queued progress"></cv-progress>
      </div>
      <div class="progress-demo-tone">
        <span>Success</span>
        <cv-progress tone="success" value="100" aria-label="Completed progress"></cv-progress>
      </div>
      <div class="progress-demo-tone">
        <span>Warning</span>
        <cv-progress tone="warning" value="58" aria-label="Paused progress"></cv-progress>
      </div>
      <div class="progress-demo-tone">
        <span>Danger</span>
        <cv-progress tone="danger" value="34" aria-label="Failed progress"></cv-progress>
      </div>
      <div class="progress-demo-tone">
        <span>Indeterminate</span>
        <cv-progress indeterminate aria-label="Waiting for remote manifest"></cv-progress>
      </div>
    </div>
  </section>
</div>

Anatomy

<cv-progress> (host)
└── <div part="base" role="progressbar">
    └── <div part="indicator">
        └── <span part="label">
            └── <slot>

Attributes

AttributeTypeDefaultDescription
valueNumber0Current progress value; clamped to [min, max]
minNumber0Minimum boundary
maxNumber100Maximum boundary
indeterminateBooleanfalseSwitches to indeterminate (animated) mode
toneStringSemantic tone: upload | queued | success | danger | warning
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 indicator (e.g. percentage text)

CSS Parts

PartElementDescription
base<div>Outer track container with role="progressbar"
indicator<div>Filled portion representing current progress
label<span>Content overlay inside indicator; wraps the default slot

Tones

ToneDescription
uploadPrimary upload/transfer progress
queuedMuted queued progress
successSuccess/completed progress
dangerFailed/error progress
warningPaused/warning progress

CSS Custom Properties

PropertyDefaultDescription
--cv-progress-height10pxBlock size (height) of the track
--cv-progress-labeled-height18pxDefault track height when label content is present and --cv-progress-height is unset
--cv-progress-track-colorvar(--cv-color-surface, #141923)Background color of the track
--cv-progress-indicator-colorvar(--cv-color-primary, #65d7ff)Base color of the filled indicator
--cv-progress-label-colorvar(--cv-color-text, #e8ecf6)Text color for the label slot content
--cv-progress-label-font-sizeCalculated from track heightFont size for the label slot content
  • The visual label is hidden when the effective track height is below 14px; progress value remains exposed through ARIA.

Visual States

Host selectorDescription
:host([indeterminate])Animated sliding bar; indicator width fixed, translateX animation
:host([data-complete])Success appearance when value >= max (uses --cv-color-success)

Reactive State Mapping

cv-progress 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 --cv-progress-width on indicator for inline-size
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 or completion logic; headless state is the source of truth.

Events

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

ChromVoid UIKit documentation