figma guide
Designing progress indicators and steppers in Figma: patterns, states, and handoff
Design linear progress bars, circular spinners, and multi-step steppers in Figma with determinate vs indeterminate states, labels, and Dev Mode handoff specs.
- Published
- Updated
- Jun 10, 2026
- Read time
- 8 min
- Level
- Beginner
Quick answer
Progress indicators in Figma show task completion—either determinate (known percentage) or indeterminate (unknown duration). Steppers show discrete steps in a multi-page flow (checkout, onboarding, settings wizard). Build linear bars and circular indicators as small published components; build steppers as horizontal or vertical step lists with variants for state=complete | current | upcoming | error. Document whether users can click ahead, what happens on back, and validation gates in Dev Mode. Pair with forms, loading states, and the Figma guides hub.
Who this is for
- Product designers shipping onboarding wizards, checkout flows, and file-upload UIs.
- Design system teams separating progress bars (within a step) from steppers (across steps).
- Engineers implementing
aria-valuenow, step validation, and non-linear navigation rules.
Progress bar vs stepper vs spinner
| Pattern | Shows | Best for | Avoid when |
|---|---|---|---|
| Linear progress bar | % complete within one task | File upload, install, profile % | Multi-page flow navigation |
| Circular progress | Compact % or indeterminate | Buttons, avatars, tight spaces | Long-form wizards |
| Indeterminate spinner | Activity without % | Unknown wait time | Upload with known file size |
| Stepper | Steps across a flow | Checkout, onboarding, settings | Single-page form |
| Skeleton screen | Content placeholder | Page load | Mid-step percentage |
Verdict: use a stepper when the user crosses multiple screens; use a progress bar when one screen tracks completion of a single task. Use skeletons for initial page loads—not steppers.
Linear progress bar anatomy
| Part | Purpose | Spec tip |
|---|---|---|
| Track | Background rail | Full width; 4–8px height |
| Fill | Completed portion | Rounded ends; animate width in code |
| Label (optional) | “68%” or “3 of 5” | Above or inside bar for large bars |
| Helper text | ”Uploading invoice.pdf” | Below bar; truncate long filenames |
ProgressBar / Linear
├── Variant: type=determinate | indeterminate
├── Variant: size=sm | md | lg
├── Property: hasLabel=true | false
├── Layer: Track (full width, radius full)
│ └── Fill (width = percentage; bind to variant or manual)
└── Label (optional, text/body-sm)
Bind track and fill to semantic tokens—progress/track, progress/fill. Use brand primary for fill; neutral gray for track.
Determinate vs indeterminate
| Type | When to use | Design note |
|---|---|---|
| Determinate | Known total (file size, steps completed) | Show percentage or fraction |
| Indeterminate | Unknown duration (API call, processing) | Animated shimmer or looping bar—no fake % |
Do not show “47%” on an indeterminate task—it erodes trust. Switch from indeterminate to determinate when the app knows progress.
Circular progress anatomy
| Part | Purpose | Spec tip |
|---|---|---|
| Track ring | Background circle | 2–4px stroke |
| Progress arc | Completed arc | Stroke-dasharray in code |
| Center label | % or icon | Optional; 32–48px total size |
Use circular progress inside buttons (“Saving…”), avatar uploads, and dashboard widgets. Keep minimum 24px diameter for visibility.
Stepper anatomy: horizontal
| Part | Purpose | Spec tip |
|---|---|---|
| Step indicator | Number or checkmark in circle | 24–32px |
| Connector line | Between steps | 2px; filled for completed segments |
| Step label | ”Shipping”, “Payment” | Below indicator; truncate on mobile |
| Optional description | Subtitle per step | Hide on compact mobile |
Stepper / Horizontal
├── Variant: stepState=complete | current | upcoming | error
├── Property: showDescription=true | false
├── Layer: Step row (vertical auto layout per step)
│ ├── Indicator circle (number or ✓)
│ ├── Label (text/label-md)
│ └── Description (optional, text/body-sm)
└── Connector (horizontal line between steps)
Publish one step component with state variants; repeat instances in a horizontal auto layout with connectors between them.
Stepper anatomy: vertical
Use vertical steppers for:
- Desktop checkout with room for descriptions
- Settings wizards with long step titles
- Timeline-style onboarding
Same complete | current | upcoming | error states. Connector runs vertically between indicators. On mobile, collapse to horizontal compact (numbers only) or a “Step 2 of 4” text summary.
Step states
| State | Indicator | Connector after | Label style |
|---|---|---|---|
| Complete | Checkmark in filled circle | Filled / brand color | Default or muted |
| Current | Number in filled circle | Unfilled ahead | Bold |
| Upcoming | Number in outline circle | Unfilled | Muted |
| Error | ! or number in error color | Unfilled or error | Error token + helper text |
Pair error steps with inline alerts on the step content—not only a red circle users cannot interpret.
Navigation rules to document
| Rule | Design decision |
|---|---|
| Click ahead to future steps? | Usually no until current validates |
| Click back to completed steps? | Usually yes; preserve entered data |
| Skip optional steps? | Show Skip link; mark step complete |
| Linear only? | Note if sidebar nav is disabled mid-flow |
| Save and exit? | Secondary action on every step |
Write these rules in the stepper component description—engineers will otherwise allow free navigation that breaks validation.
Steppers with forms
Each step frame should contain:
- Stepper header (instance)
- Step content (form fields from forms guide)
- Footer actions: Back (secondary), Continue (primary), optional Save draft
| Step type | Primary button label |
|---|---|
| Middle steps | ”Continue” or “Next” |
| Final step | ”Submit”, “Place order”, “Finish” |
| Payment | ”Pay now” |
Disable Continue until required fields pass validation—show disabled button state in the component set.
Progress within a step
Combine stepper + linear bar when one step has sub-tasks:
- Step 3: Upload documents — bar shows 2 of 4 files uploaded
- Profile setup — bar shows profile 80% complete before “Continue” enables
Keep the bar inside the step content area, not in the stepper header, to avoid two competing progress metaphors at the same level.
Accessibility
| Element | Requirement |
|---|---|
| Linear bar | role="progressbar", aria-valuenow, aria-valuemin, aria-valuemax |
| Indeterminate bar | aria-busy="true"; no misleading valuenow |
| Stepper | aria-current="step" on current step |
| Error step | aria-invalid + linked error message |
| Color | Do not rely on green/red alone—use icons (✓, !) |
Announce step changes with a live region in engineering (“Step 2 of 4: Payment”). Minimum 44px touch targets on step indicators if they are clickable.
Prototyping limits
Figma cannot enforce validation between steps. For reviews:
- Build frames: Step 1, Step 2, Step 3 complete.
- Prototype Continue → next frame; Back → previous.
- Add a disabled Continue frame showing validation failure.
- Note: “Engineering: block advance until schema passes.”
For determinate bars, show 0%, 50%, and 100% as separate component variants—not a single animating layer.
Handoff to engineering
| Deliverable | Where it lives |
|---|---|
| Step count and labels | Stepper component properties |
| Navigation rules (ahead/back) | Component description |
| Validation per step | Linked form spec or table |
| Progress calculation | Dev Mode note (file bytes, fields filled) |
| Mobile collapse behavior | sm artboard with compact stepper |
| Error recovery | Error variant + alert placement |
Include steppers in your Dev Mode handoff checklist. Publish under Patterns / Stepper and Patterns / Progress in your team library.
Real-world examples
E-commerce checkout (horizontal stepper)
Steps: Cart → Shipping → Payment → Review. No click-ahead. Back preserves cart. Final step uses modal confirm for place order.
File upload (linear determinate bar)
Single page; bar fills by bytes uploaded. Switch to error state with inline alert on failure; retry action resets bar.
Onboarding wizard (vertical stepper)
Four steps with descriptions. Optional “Skip tour” on step 1. Last step shows empty state CTA to create first project.
Cross-link wireframing when step flows are still in lo-fi review.
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Fake % on unknown waits | Users lose trust | Indeterminate until known |
| Stepper for single long form | Unnecessary friction | One page + section headings |
| Clickable future steps | Broken validation | Disable or hide ahead navigation |
| No error state on steps | Users stuck | error variant + message |
| Tiny step circles on mobile | Mis-taps | 32px min or compact text mode |
| Two progress bars stacked | Visual noise | One metaphor per level |
| Step labels truncate to ”…” | Users lost | Short labels; tooltip on hover |
| Spinner for 30s upload | No sense of time | Determinate bar with % |
FAQ
Should the stepper and progress bar share one component?
No. Steppers navigate across pages; progress bars track within a task. Share color tokens and size scale only.
How is this different from loading skeletons?
Skeletons replace content layout during fetch. Progress bars show task completion for actions the user initiated (upload, submit, install).
Show step numbers or icons only?
Numbers for flows up to ~5 steps. Switch to icons + short labels only when steps are universally understood (✓ cart, card, truck). Always include a text label for accessibility.
Include a percentage in onboarding steppers?
Usually no—use “Step 2 of 4” text instead. Percentages fit profile completion or upload contexts, not arbitrary wizard pages.
Bottom line
Use linear or circular progress for single-task completion (known or unknown duration) and steppers for multi-step flows with clear complete, current, upcoming, and error states. Document navigation rules, validation gates, and mobile collapse in Dev Mode. Continue with forms, modals for final confirms, and the tutorials hub.
§ Keep reading