DEV Community

WDSEGA
WDSEGA

Posted on

Component Deep Dive #25: Progress Bar - The Unsung Hero of User Patience

Component Deep Dive #25: Progress Bar

Users don't care how elegant your code is. They care about one thing: how much longer?

The Progress Bar is one of the most underrated components in web development. It's not flashy, it's not complex, but it directly determines whether users stay on your page. A loading process without progress feedback loses 50% of users in 3 seconds.

Why Not <progress>?

HTML5 provides a native <progress> tag, but you almost never see it in production. Browser default styles vary wildly between Safari and Chrome, and customizing them requires extensive ::-webkit-progress-bar and ::-moz-progress-bar pseudo-element hacks. You'll find that building your own with div gives you more control and consistency.

Core Implementation

CSS Custom Properties Drive Everything

.progress__bar {
  width: var(--progress, 0%);
  height: 100%;
  background: linear-gradient(90deg, #6366f1, #8b5cf6);
  transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
Enter fullscreen mode Exit fullscreen mode

The key insight: use a CSS custom property --progress to drive the width, not style.width directly. This way, you update one variable in JS and CSS handles the transition automatically.

Indeterminate State

When you don't know the actual progress (e.g., waiting for server response), use an indeterminate animation - a 40% bar sliding back and forth. The user sees "it's moving, still processing" instead of "it's frozen."

prefers-reduced-motion

99% of progress bar implementations ignore this:

@media (prefers-reduced-motion: reduce) {
  .progress__bar { transition: none; }
  .progress__bar--indeterminate { animation: none; }
}
Enter fullscreen mode Exit fullscreen mode

For users with vestibular disorders, continuous animation can cause discomfort. Respect their system settings.

Color Changes with Progress

.progress__bar {
  --hue: calc(var(--progress) * 1.2);
  background: hsl(var(--hue), 70%, 50%);
}
Enter fullscreen mode Exit fullscreen mode

0% = red (hue 0), 100% = green (hue 120). calc() can operate on CSS custom properties directly.

Common Pitfalls

  1. Don't animate width: 100% - triggers Layout. Use transform: scaleX() instead
  2. Don't forget aria-valuenow - screen reader users need progress too
  3. Don't frequently switch between determinate and indeterminate - confuses users
  4. Don't let progress stick at 99% - either show real progress or use indeterminate

The core of a progress bar isn't visual - it's psychological. It tells users "the system is working, please wait."


This article was first published on Deskless Daily. Follow for more AI-driven tech content.

Top comments (0)