Progress

A linear progress indicator communicating the completion of an operation. Settld uses a teal fill on a warm ink-line track. The subtle 4px height keeps it unobtrusive during processing states; the prominent 8px height is used when progress is the primary focus.

Variants

Uploading receipt 68%
Syncing expenses Syncing…
Processing payment ₹840 of ₹1,200

Determinate — use when you can calculate the actual percentage. Show a numeric label when the number is meaningful (upload bytes, settlement amount). Animate width with transition: width 240ms ease-out as values update.

Indeterminate — use when you know something is happening but not how far along it is. A 40%-wide fill sweeps left to right at 1.6s. Never fake a percentage for an indeterminate operation.

Sizes

Subtle — 4pxUsed for uploads, background sync
Prominent — 8pxUsed for settlement processing
SizeClassHeightUse case
Subtle.progress--subtle4pxFile uploads, image processing, background sync — when progress shouldn't steal focus
Prominent.progress--prominent8pxSettlement processing, onboarding steps — when progress is the primary signal

States

Empty / not started0%
In progress42%
Complete100%
ErrorFailed
IndeterminateSyncing…
StateFill widthFill colorAnimation
Empty0%--teal
In progressN%--tealwidth transition 240ms ease-out
Complete100%--successwidth transition 240ms ease-out
ErrorFrozen at failure point--coral
Indeterminate40% (swept)--tealSlide 1.6s ease-ios infinite

Color variants

The default fill is teal. Use --coral for error states, --success for completed states. Warning amber is used for cap meters (free tier approaching limit). Don't use color alone to convey state — pair it with a label.

On dark surfaces

Uploading receipt 68%
Syncing Syncing…

On dark surfaces, the track switches from --ink-line to --dark-border. The teal fill doesn't change — it has sufficient contrast on both surfaces.

Anatomy

Uploading receipt 68%
Track (--ink-line)
Fill (--teal)
PartElementNotes
Wrapperdiv.progress-wrapperOptional — flex column with 6px gap for label + bar.
Label rowdiv.progress-labelOptional — flex between label text and value/percentage.
Trackdiv[role="progressbar"]Full-width, overflow: hidden, warm ink-line color.
Filldiv.progress__fillWidth set by style="width:N%". Teal by default.

Usage

Do Use determinate progress with a percentage label when uploading files or processing a UPI payment. Animate the width smoothly as values update — a jump feels broken.
Don't Don't fake progress with a timer. Don't show a progress bar for operations that take less than 300ms — the flash is worse than nothing. Don't use progress for navigation steps (use a stepper).
Do Use indeterminate for operations where you genuinely can't know progress: cloud sync, API calls. Always pair with a descriptive label ("Syncing with Rohan's phone").
Don't Don't leave an indeterminate bar running indefinitely — set a timeout and switch to an error state with a retry action. Don't use a circular spinner and a linear bar for the same state.

Accessibility

ARIA Always use role="progressbar" with aria-valuenow, aria-valuemin="0", aria-valuemax="100", and aria-label describing the operation. For indeterminate bars, omit aria-valuenow — screen readers announce "in progress" automatically.
Motion The indeterminate animation runs continuously. Respect prefers-reduced-motion — when the user has reduced motion enabled, pause the animation and show a static 40% fill instead.
Color Teal fill on ink-line track: 3.2:1 ratio. This meets WCAG AA for large UI components. Never rely on color alone to indicate the state — always pair with a text label.

Code

HTML

<!-- Determinate with label -->
<div class="progress-wrapper">
  <div class="progress-label">
    <span>Uploading receipt</span>
    <span class="progress-label__value">68%</span>
  </div>
  <div class="progress progress--subtle"
       role="progressbar"
       aria-valuenow="68"
       aria-valuemin="0"
       aria-valuemax="100"
       aria-label="Uploading receipt">
    <div class="progress__fill" style="width: 68%"></div>
  </div>
</div>

<!-- Indeterminate -->
<div class="progress progress--subtle progress--indeterminate"
     role="progressbar"
     aria-label="Syncing expenses">
  <div class="progress__fill"></div>
</div>

<!-- Prominent, complete state -->
<div class="progress progress--prominent progress--success"
     role="progressbar"
     aria-valuenow="100"
     aria-valuemin="0"
     aria-valuemax="100"
     aria-label="Settlement complete">
  <div class="progress__fill" style="width: 100%"></div>
</div>

CSS classes

ClassPurpose
.progressTrack — full width, overflow hidden, rounded
.progress--subtle4px height — uploads, background tasks
.progress--prominent8px height — settlement, primary process
.progress--indeterminateSweeping shimmer animation
.progress--tealTeal fill (default)
.progress--coralCoral fill — error state
.progress--successSuccess green fill — complete state
.progress--warningAmber fill — cap approaching
.progress__fillFill bar — width controlled by inline style
.progress-wrapperColumn flex wrapper for label + bar
.progress-labelLabel row — space-between flex
.progress-label__valueRight-aligned value in mono

Design tokens used

TokenValueRole
--ink-line#DDD2B8Track background
--teal#0E7C66Default fill color
--coral#E76F51Error fill color
--success#0E7C66Complete fill color
--warning#D4940ACap warning fill color
--d-med240msWidth transition duration
--ease-outcubic-bezier(0.23,1,0.32,1)Width transition easing
--ease-ioscubic-bezier(0.32,0.72,0,1)Indeterminate sweep easing