Skip to main content

Loading Progress

Progress bars with animations, time estimates, and customizable variants for tracking loading operations

Loading Progress

The LoadingProgress component provides visual progress indicators with animations, time estimates, and customizable styling for tracking the completion of operations.

Overview

Progress bars are essential for operations that take more than a few seconds, providing users with clear feedback about completion status and remaining time. They help manage user expectations and reduce perceived wait times.

Interactive Demo

Interactive Progress Bar

Control progress value and watch real-time updates

Progress: 45%
Processing...
45% 2 seconds remaining
Progress Control
Use slider to control progress value
Size:
Variant:
Configuration preview
75% 2 seconds remaining
Configuration Options
Toggle display options and styling

API Reference

Props

PropTypeDefaultDescription
progressLoadingProgressRequiredProgress data object
size'sm' \| 'md' \| 'lg''md'Progress bar height
variant'default' \| 'striped' \| 'animated''default'Visual variant
showMessagebooleantrueDisplay progress message
showPercentagebooleantrueDisplay percentage value
showTimeRemainingbooleanfalseDisplay estimated time remaining

LoadingProgress Object

PropertyTypeDescription
currentnumberCurrent progress value
totalnumberTotal/maximum value
percentagenumberCalculated percentage (0-100)
messagestringProgress description
estimatedTimeRemainingnumberTime remaining in milliseconds

Usage Examples

Basic Progress Tracking

<script>
import LoadingProgress from '$lib/loading/components/LoadingProgress.svelte';

let uploadProgress = $state({
  current: 0,
  total: 100,
  percentage: 0,
  message: 'Preparing upload...',
  estimatedTimeRemaining: 0
});

async function uploadFile(file) {
  const formData = new FormData();
  formData.append('file', file);

  const xhr = new XMLHttpRequest();

  xhr.upload.onprogress = (event) => {
    if (event.lengthComputable) {
      const percentComplete = (event.loaded / event.total) * 100;
      uploadProgress = {
        current: event.loaded,
        total: event.total,
        percentage: percentComplete,
        message: percentComplete < 100 ? 'Uploading file...' : 'Processing...',
        estimatedTimeRemaining: calculateTimeRemaining(percentComplete)
      };
    }
  };

  xhr.onload = () => {
    uploadProgress.message = 'Upload complete!';
    uploadProgress.percentage = 100;
  };

  xhr.open('POST', '/api/upload');
  xhr.send(formData);
}
</script>

<LoadingProgress
  progress={uploadProgress}
  size="md"
  variant="animated"
  showMessage={true}
  showPercentage={true}
  showTimeRemaining={uploadProgress.percentage > 0 && uploadProgress.percentage < 100}
/>

Form Processing Progress

<script>
let formSubmission = $state({
  current: 0,
  total: 5,
  percentage: 0,
  message: 'Ready to submit',
  estimatedTimeRemaining: 0
});

let isSubmitting = $state(false);

async function handleSubmit() {
  isSubmitting = true;

  const steps = [
    { message: 'Validating form data...', duration: 800 },
    { message: 'Connecting to server...', duration: 600 },
    { message: 'Processing request...', duration: 1200 },
    { message: 'Saving changes...', duration: 1000 },
    { message: 'Complete!', duration: 500 }
  ];

  for (let i = 0; i < steps.length; i++) {
    const step = steps[i];
    formSubmission = {
      current: i + 1,
      total: steps.length,
      percentage: ((i + 1) / steps.length) * 100,
      message: step.message,
      estimatedTimeRemaining: steps.slice(i + 1).reduce((sum, s) => sum + s.duration, 0)
    };

    await new Promise(resolve => setTimeout(resolve, step.duration));
  }

  isSubmitting = false;
}
</script>

{#if isSubmitting}
  <LoadingProgress
    progress={formSubmission}
    size="lg"
    variant="striped"
    showMessage={true}
    showPercentage={true}
    showTimeRemaining={true}
  />
{/if}

Indeterminate Progress

For operations where progress cannot be measured:

<script>
let indeterminateProgress = $state({
  current: 0,
  total: 100,
  percentage: 0, // 0 triggers indeterminate animation
  message: 'Processing request...',
  estimatedTimeRemaining: 0
});
</script>

<LoadingProgress
  progress={indeterminateProgress}
  variant="animated"
  showMessage={true}
  showPercentage={false}
  showTimeRemaining={false}
/>

Multi-step Process

<script>
const processingSteps = [
  'Analyzing data',
  'Applying transformations',
  'Generating report',
  'Finalizing output'
];

let currentStep = $state(0);
let stepProgress = $state(0);

$: overallProgress = {
  current: currentStep * 100 + stepProgress,
  total: processingSteps.length * 100,
  percentage: ((currentStep * 100 + stepProgress) / (processingSteps.length * 100)) * 100,
  message: `${processingSteps[currentStep]} (${currentStep + 1}/${processingSteps.length})`,
  estimatedTimeRemaining: calculateRemainingTime(currentStep, stepProgress)
};
</script>

<LoadingProgress
  progress={overallProgress}
  size="md"
  variant="default"
  showMessage={true}
  showPercentage={true}
  showTimeRemaining={true}
/>

Variants

Default

Clean, solid progress bar with smooth transitions.

  • Use for: Standard progress tracking
  • Style: Solid color fill
  • Animation: Smooth width transitions

Striped

Progress bar with diagonal stripe pattern.

  • Use for: Active processes, downloads
  • Style: Diagonal stripe pattern
  • Animation: Static stripes with width animation

Animated

Progress bar with shimmer animation effect.

  • Use for: Premium feel, important operations
  • Style: Gradient shimmer effect
  • Animation: Moving shimmer overlay

Size Guidelines

Small (sm)

  • Height: 4px
  • Use for: Subtle progress indicators, inline elements
  • Best with: Minimal text, percentage only

Medium (md) - Default

  • Height: 8px
  • Use for: Standard progress bars, form sections
  • Best with: Progress message and percentage

Large (lg)

  • Height: 12px
  • Use for: Primary loading states, important processes
  • Best with: Full information display, time estimates

Time Estimation

The component can display estimated time remaining based on current progress:

// Calculate time remaining based on progress rate
function calculateTimeRemaining(startTime, currentProgress) {
  const elapsed = Date.now() - startTime;
  const rate = currentProgress / elapsed; // progress per ms
  const remaining = (100 - currentProgress) / rate;
  return Math.max(0, remaining);
}

// Format duration for display
function formatDuration(milliseconds) {
  const seconds = Math.ceil(milliseconds / 1000);

  if (seconds < 60) return `${seconds}s`;
  if (seconds < 3600) return `${Math.ceil(seconds / 60)}m`;
  return `${Math.ceil(seconds / 3600)}h`;
}

Accessibility Features

ARIA Support

  • role="progressbar": Identifies the progress element
  • aria-valuenow: Current progress value
  • aria-valuemin: Minimum value (0)
  • aria-valuemax: Maximum value (100)
  • aria-label: Descriptive label for screen readers

Screen Reader Announcements

  • Progress updates are announced at reasonable intervals
  • Completion status is clearly communicated
  • Time estimates are announced when available

Visual Indicators

  • High contrast colors for visibility
  • Clear percentage and message text
  • Adequate size for touch targets (when interactive)

Best Practices

When to Use Progress Bars

Use progress bars for:

  • File uploads/downloads (measurable progress)
  • Form submissions with multiple steps
  • Data processing operations
  • Installation or setup processes
  • Batch operations with known total

Don’t use progress bars for:

  • Operations under 2 seconds (use spinners)
  • Indeterminate operations (use loading text)
  • Simple API calls (use loading states)

Progress Communication

Messages should be:

  • Action-oriented: “Uploading file…” not “Upload”
  • Specific: “Processing 3 of 10 images” not “Processing”
  • Reassuring: “Almost done…” not “Please wait”
  • Consistent: Use similar phrasing across your app

Time estimates should be:

  • Conservative: Better to underestimate than overestimate
  • Updated: Recalculate based on actual progress rate
  • Hidden for short operations: Don’t show for < 10 seconds
  • Formatted appropriately: Use human-readable units

Performance Considerations

  • Update progress at reasonable intervals (not every percent)
  • Batch progress updates to avoid excessive re-renders
  • Use smooth CSS transitions rather than frequent updates
  • Clean up timers and intervals on component unmount