Pular para o conteúdo

Progress indicators

components specs/components/progress-indicators.kmd

Visual feedback that an operation is in progress — linear (bar) or circular (spinner), determinate (known %) or indeterminate (unknown duration). Material parity (`/components/progress-indicators`).

Quando esta spec se aplica

Triggers primários

Todos os triggers

Corpo da especificação

Spec — Progress indicators

Facet Visual of Koder Design. Material parity: https://m3.material.io/components/progress-indicators.

2 shapes × 2 modes

Shape \ ModeDeterminateIndeterminate
LinearBar fills 0 → 100%Sliding band animates left → right (no fill)
CircularArc sweeps 0 → 360°Arc rotates continuously

Pick:

  • Shape: linear when there's horizontal real estate (above content, banner-like); circular when space is constrained (button, dialog, icon-sized).
  • Mode: determinate when % is known (file upload); indeterminate when not (network handshake, ML inference).

Anatomy (linear, determinate)

   45% complete
   ████████░░░░░░░░░░░░░░░░░░░░░
   ←──────── 100% ────────────→
  • Track height: 4 px (default) / 8 px (large)
  • Track bg: surface-container-highest (or primary 12%)
  • Active fill: primary color
  • Corner radius: track height / 2 (pill shape)
  • Stop point (Material 3): 4 px circle of primary color at the end of the track to indicate "track end"

Anatomy (circular):

       ╭ ━━━╮
       ┃    ╲
       ┃     ●    ← stroke head
       ╲    ╱
        ╲ ━╱
  • Diameter: 24 px (small) / 32 px (default) / 48 px (large)
  • Stroke width: 4 px (default), scales with size
  • Track: surface-container-highest ring
  • Active arc: primary color

R1 — Linear determinate

  • Fill animates from current % to new % (motion-fast, ~150 ms)
  • Don't reset to 0 between updates — smooth interpolation
  • At 100%: brief settle (stop-point disappears as track ends)
  • Backwards progress (resume after pause) allowed — animate back

R2 — Linear indeterminate

  • Sliding band: 30-50% of track width, slides left → right continuously
  • Cycle duration: 2 s
  • Easing: cubic ease-in-out
  • No stop point in indeterminate mode

R3 — Circular determinate

  • Arc length proportional to %
  • Starts at 12 o'clock; sweeps clockwise
  • Stroke ends with rounded cap

R4 — Circular indeterminate

  • Full circle rotates clockwise: 1.5 s per rotation
  • Arc length pulses: 25% → 75% → 25% over 1 cycle
  • Two pulses per rotation (Material 3 default; document if changed)

R5 — Buffer indicator (linear only)

For media / download with "buffered ahead of playhead":

   ████████████░░░░░░░░░░░░░░░░░░░
   ━━━━━━━━━━━━━━━━━░░░░░░░░░░░░░░
   ↑               ↑
   playhead (filled)
                   buffered (lighter)
  • Buffer color: primary 40% (lighter than active)
  • Buffer always ≥ playhead position

R6 — Indicator placement

PlacementUse
Above content (full-width linear)Page-level loading
In-button (small circular replaces text)Submitting a form
Inline next to label (24 px circular)Item-level operation (e.g., row syncing)
Centered in container (large circular)Empty card / pane loading
In app bar bottom edge (linear)Long page operations (refresh)

R7 — Combine with action button

When a button triggers a long operation, replace its content with a small circular indicator (24 px):

  Before: [   Submit   ]
  During: [    ◐       ]   ← circular indeterminate, 24 px
  After:  [✓  Saved   ]
  • Button width stays the same (avoid layout shift)
  • Disable the button during operation
  • On success: brief check icon (1 s) before reverting to idle / new label

R8 — Multi-step / segmented (linear)

Linear can show discrete steps:

   ███ ███ ███ ░░░ ░░░    Step 3 of 5
   step1 step2 step3 step4 step5
  • 2 px gap between segments
  • Each segment radius = track height / 2
  • Filled segments use active color; unfilled use track color

Used for: onboarding stepper, multi-page form indicator.

R9 — Empty / not-started state

Don't show the indicator at 0% — looks broken. Either:

  • Show indicator only after operation starts (delay 200-400 ms)
  • Begin animation as soon as visible (indeterminate)

For determinate, if value is genuinely 0, render the track only (no fill) and show "0%" or "Not started" label nearby.

R10 — Completion state

Determinate at 100%:

  • Brief settle (200 ms)
  • Fade out indicator OR replace with success icon (✓)
  • For background operations, fade out after 1-2 s

R11 — Accessibility

  • Determinate linear / circular: role="progressbar" + aria-valuenow / aria-valuemin / aria-valuemax + aria-label describing what's loading
  • Indeterminate: role="progressbar" + aria-busy="true" + no aria-valuenow (omitted means indeterminate per ARIA)
  • For long operations, periodically announce progress to screen reader (e.g., every 25%): aria-live="polite" on container
  • Don't rely on color alone — pair with text label ("45% complete") for determinate

R12 — Animation

  • Determinate update: motion-fast (~150 ms) interpolation
  • Indeterminate linear cycle: 2 s
  • Indeterminate circular cycle: 1.5 s
  • All animations respect prefers-reduced-motion:
    • Linear indeterminate: pulsing opacity 50% → 100% instead of sliding
    • Circular indeterminate: no rotation; opacity pulse instead

R13 — States

Progress indicators don't have hover / pressed / focused states (they're decorative output, not interactive).

Disabled state IS valid — operation cancelled:

  • Indicator fades to 38% opacity
  • Active animation stops
  • Track stays visible briefly before fading entirely

R14 — Density

DensityLinear heightCircular default
Compact2 px20 px
Default4 px32 px
Comfortable8 px48 px

R15 — Per-preset variation

PresetLinearCircular
material3Track + stop point at endStroke with rounded cap, 2 pulses/rotation
material2No stop point; flat endsFull rotation, 1 pulse
ios_cupertinoSolid bar without stopUIActivityIndicator gear-style
gnomeGtkProgressBar styleAdwaita spinner (3 dots)
windows_11Accent bar with subtle glowFluent spinner (dots circling)
brutalistSolid block, no easing (step changes only)Square instead of circle, hard rotation
terminal_classic[██████░░░░] 60% ASCIISpinner cycle `

R16 — Forbidden patterns

  • ❌ Indeterminate when % is actually known (defeats user trust)
  • ❌ Multiple progress indicators stacked on the same operation
  • ❌ Indicator < 24 px for circular (unreadable)
  • ❌ Animation that resets to 0 between % updates
  • ❌ Showing indicator for < 200 ms (annoying flash; either delay it or do without)
  • ❌ Operation that runs > 30 s with no progress feedback (always show indicator)
  • ❌ Indicator without label / context (user can't tell WHAT is loading)
  • ❌ Hiding the button label entirely on submit without a replacement (no feedback that work started)
  • themes/motion.kmd — easing for indeterminate cycle
  • themes/color-roles.kmdprimary for active, surface-container-highest for track
  • interaction/states.kmd — disabled overlay
  • components/buttons.kmd — in-button progress pattern
  • foundations/elements.kmd — Output family

Referências