Zetta v1.6

Components · Data display & feedback

Progress

A determinate completion bar — an 8px track with a primary fill. Use it when the amount of work is known; use Spinner for indeterminate operations.

Preview

Build with the skill

No package to install — hand this to your AI to generate or migrate the component in your stack.

Prompt for your AI
Apply the Zetta "Progress" component to this project using the zetta-design-md skill.

WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `progress` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `progress` spec in this project's stack.

AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.

ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility.

Anatomy & rules

[████████░░░░░░░░░░░░]  64%   ← progress-bar (determinate)
[▓▓▓▓▓▓▓▓████░░░░░░░]       ← progress-bar-indeterminate (sweeping animation)

  ⟳   ← progress-spinner
State Fill Track
Default {colors.primary} {colors.surface-muted}
Success {colors.success} {colors.success-bg}
Danger / Error {colors.danger} {colors.danger-bg}
Indeterminate Animated shimmer {colors.surface-muted}
Complete (100%) {colors.success} {colors.success-bg}

When to use

  • File uploads, form submissions, multi-step processes (bar, determinate).
  • Data fetching, background sync, initial page load (spinner or indeterminate bar).

When not to use

  • Instant operations (< 300ms) — don't flash a spinner for imperceptible waits.
  • Skeleton loading — prefer Skeleton for content placeholders.

Do

  • Show determinate bar when progress percentage is known — it reduces perceived wait time.
  • Show spinner only when the operation cannot be measured.
  • Display a progress label when the bar value alone lacks context ("Uploading 3 of 10 files").

Don't

  • Don't use both a spinner and a bar for the same operation.
  • Don't animate the bar width with a sudden jump — always use transition.
  • Progress label: match the action verb — "Uploading…", "Processing…", "Generating…". Include quantity when known: "Uploading 3 of 10 files".
  • Spinner label (visually hidden): short present-participle phrase: "Loading", "Saving", "Submitting". Never "Please wait…".
  • Completion announcement: after operation ends, update the live region to a past-tense phrase: "Upload complete", "Saved".

Keyboard

Progress Indicator is non-interactive and has no keyboard behavior.

Accessibility

  • Bar determinate: role="progressbar" with aria-valuenow, aria-valuemin="0", aria-valuemax="100", and aria-label.
  • Bar indeterminate: role="progressbar" — omit aria-valuenow.
  • Spinner: role="status" with a visually hidden <span> containing the status label (e.g. "Loading…").
  • After loading completes, update the live region to announce completion: "Upload complete".

Spec

Values and token references resolved straight from the Zetta spec.

progress-bar
height
4px
borderRadius
{rounded.full}
backgroundColor
{colors.surface-muted}
overflow
hidden
progress-bar-fill
height
100%
borderRadius
{rounded.full}
backgroundColor
{colors.primary}
transition
width {motion.duration-base} {motion.easing-default}
progress-bar-indeterminate
backgroundColor
{colors.primary}
animation
indeterminate {motion.duration-slow} {motion.easing-default} infinite
progress-bar-success
backgroundColor
{colors.success}
progress-bar-danger
backgroundColor
{colors.danger}
progress-bar-sm
height
2px
progress-bar-lg
height
8px
progress-spinner
width
20px
height
20px
borderWidth
2px
borderStyle
solid
borderColor
{colors.surface-muted}
borderTopColor
{colors.primary}
borderRadius
{rounded.full}
animation
spin {motion.duration-slow} linear infinite
progress-spinner-sm
width
14px
height
14px
borderWidth
1.5px
progress-spinner-lg
width
32px
height
32px
borderWidth
3px
progress-spinner-fullscreen
width
50px
height
50px
borderWidth
4px
borderStyle
solid
borderColor
{colors.surface-muted}
borderTopColor
{colors.primary}
borderRadius
{rounded.full}
animation
spin {motion.duration-slow} linear infinite
position
fixed
top
50%
left
50%
transform
translate(-50%, -50%)
zIndex
{elevation.z-index.modal}
progress-spinner-invert
borderColor
rgba(255,255,255,0.25)
borderTopColor
{colors.canvas}
progress-label
fontFamily
Geist
fontSize
12px
fontWeight
400
textColor
{colors.muted}
marginTop
{spacing.xs}

Known gaps

  • progress-spinner-invert arc color — currently hardcoded to rgba(255,255,255,0.25) (track) and {colors.canvas} (arc). No semantic token covers this use case cleanly.
  • Fullscreen spinner blanket — progress-spinner-fullscreen positions the spinner but the blanket overlay behind it is product responsibility. A dedicated fullscreen-loading composite pattern is not yet specified.
  • Progress bar success/error visual state transition animation — not yet specified.