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
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
progress | LoadingProgress | Required | Progress data object |
size | 'sm' \| 'md' \| 'lg' | 'md' | Progress bar height |
variant | 'default' \| 'striped' \| 'animated' | 'default' | Visual variant |
showMessage | boolean | true | Display progress message |
showPercentage | boolean | true | Display percentage value |
showTimeRemaining | boolean | false | Display estimated time remaining |
LoadingProgress Object
| Property | Type | Description |
|---|---|---|
current | number | Current progress value |
total | number | Total/maximum value |
percentage | number | Calculated percentage (0-100) |
message | string | Progress description |
estimatedTimeRemaining | number | Time 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 elementaria-valuenow: Current progress valuearia-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