Progress Bar
A determinate indicator showing how much of a known task is done — usable only when the total is actually known.
A progress bar is a determinate indicator: it shows how much of a known task is done. The word determinate is the condition — it works only where the total is genuinely known.
That distinguishes it from a spinner, which reports that work is happening and nothing about how much remains. Where the total is knowable, a bar is strictly better, because a number moving is far easier to wait through than an animation that does not.
Use it wherever the total is known
Uploads, imports, exports, batch operations, multi-step jobs. All of these know how many bytes or records there are, and all of them routinely ship with a spinner because the spinner was easier.
Show units, not only a percentage. "340 of 1,200 records" tells somebody more than "28%", and it survives a stall more honestly — a count that has not moved in thirty seconds is legible in a way a static bar is not.
Be careful with time estimates. An estimate that swings from two minutes to fourteen and back destroys confidence in everything else on the screen. Where timing is unpredictable, show the count and omit the time.
Never fake the last stretch. Bars that ease slowly toward 99% while waiting are a small lie, and people learn to distrust the whole indicator.
What happens when it stalls
A bar sitting at 97% forever is worse than an error, because the person waits rather than acting.
Detect the stall. A timeout on progress, not only on the request.
Switch to an error state with a retry, and say what happened. See error state.
Say what survived. In a batch operation, three hundred of twelve hundred records may already be processed. Whether the retry resumes or restarts is something the person needs to know before pressing it.
Past ten seconds, reconsider the pattern
Nielsen's response time limits put ten seconds at the outer edge of held attention. Beyond it, people go and do something else — and a blocking interface prevents exactly that.
The right answer for long operations is a background job: start it, let the person leave, tell them when it is done. In B2B this is not a refinement — imports and exports routinely run for minutes, and an interface that holds somebody hostage for the duration is a design decision made by default.
Where the work must block, the bar needs a cancel, and cancel has to actually stop the work rather than only hiding the dialog.
Progress bar against a stepper
They look similar and describe different things.
A progress bar measures one task's completion. A stepper shows position in a sequence of discrete stages. Using a bar for a five-step form implies a continuous quantity where there are five named things, and loses the labels that make the sequence legible.
Accessibility
The progressbar role with current and maximum values.
Announce changes meaningfully, not every percent. A screen reader reciting each increment is unusable; announcements at intervals, or on completion, are not.
The number must exist as text. A bar with no figure beside it communicates nothing to anybody who cannot see it, and very little to anybody who can.
Respect reduced motion on any animated fill.
In practice
A bulk import shows a spinner while it runs. The import takes between forty seconds and four minutes depending on file size, and support hears from customers who reloaded the page mid-import because they assumed it had hung.
Reloading during the import produced duplicate records, which is the actual cost of the missing indicator.
Replacing it with a determinate bar showing records processed, plus a line saying the import continues if the page is closed, removes both problems. The duplicates stop because nobody reloads, and the support tickets stop because nobody has to guess.
The import was never slow enough to be the problem. It was silent, which is a different failure with a different fix.
Where teams get it wrong
- A spinner where the total is known. The harder wait, chosen by default.
- Percentages with no units. Less information, and a stall that reads as motion.
- Optimistic estimates. One wrong figure and nothing on screen is trusted.
- Stalling silently at 97%. People wait instead of acting.
- Blocking for minutes. A background job, refused.
- A bar with no number. Nothing communicated to anybody who cannot see it.
Learn more
Frequently Asked Questions
Related terms