Back to Dictionary
Waiting & Loading
●○○Ready to Use

Progress Bar

Choose a progress bar when the user needs confidence about how much work remains.

Timing

Animate width changes in 200-400ms; for multi-second tasks, update with real measured increments.

Easing

Ease-out individual width updates, but never fake smooth motion that hides actual task state.

Risk

misleading progressfeels slow

Live Demo

0%

What It Is

A horizontal bar that fills from left to right, showing the percentage of a task that's complete. Gives users a sense of how much longer they need to wait.

Decision Guidance

Choose a progress bar when the user needs confidence about how much work remains.

Best For

Uploads, imports, setup flows, and long tasks where the app can measure completion.

Avoid When

Avoid when progress is unknown or the system may stall near the end.

Timing

Animate width changes in 200-400ms; for multi-second tasks, update with real measured increments.

Easing

Ease-out individual width updates, but never fake smooth motion that hides actual task state.

Risk Tags

misleading progressfeels slow

When to Use

  • File uploads or downloads where progress is trackable
  • Multi-step forms or onboarding flows ("Step 2 of 5")
  • Data processing with measurable completion (e.g., import progress)
  • Any wait over 3 seconds where percentage completion is known

When NOT to Use

  • When you don't know actual progress (use indeterminate spinner instead)
  • Very fast operations under 1 second
  • When the progress is unpredictable or could move backwards

You've Seen It In

YouTubeStripe CheckoutGitHub ActionsNotion Import

Prompt Templates

Copy and paste these prompts into your AI coding assistant.

Create a progress bar that shows completion percentage. The bar should fill from left to right with smooth transitions. Display the percentage number.

Code Example (Tailwind CSS)

export function ProgressBar({ 
  progress, 
  showLabel = true,
  variant = 'primary' 
}: { 
  progress: number; 
  showLabel?: boolean;
  variant?: 'primary' | 'success' | 'error';
}) {
  const colors = {
    primary: 'bg-amber-warm',
    success: 'bg-green-500',
    error: 'bg-red-500',
  };
  
  return (
    <div className="w-full">
      <div className="h-2 w-full overflow-hidden rounded-full bg-zinc-800">
        <div
          className={`h-full transition-all duration-300 ease-out ${colors[variant]}`}
          style={{ width: `${Math.min(100, Math.max(0, progress))}%` }}
        />
      </div>
      {showLabel && (
        <div className="mt-2 text-right text-sm text-zinc-400">
          {Math.round(progress)}%
        </div>
      )}
    </div>
  );
}