Ask AI about this page

Introduction

The Progress component provides a flexible and accessible way to display progress indicators, loading states, and completion tracking. It supports both determinate (known progress) and indeterminate (unknown duration) states, buffer visualization for streaming content, and extensive customization options. Perfect for file uploads, form completion, video buffering, data processing, and any scenario requiring progress visualization.

Installation

Use the Sheaf artisan command to install the progress component:

php artisan sheaf:install progress

Once installed, you can use <x-ui.progress /> in any Blade view.

Basic Usage

25% Progress
50% Progress
75% Progress
100% Complete
<!-- Static progress values -->
<div class="space-y-2">
    <x-ui.text size="sm" class="font-medium">25% Progress</x-ui.text>
    <x-ui.progress value="25" />
</div>
<x-ui.progress value="50" />
<x-ui.progress value="75" />
<x-ui.progress value="100" />

Size Variants

The progress bar comes in five sizes, from extra small to extra large. Control the height using the size prop:

Extra Small (xs)
Small (sm)
Medium (md) - Default
Large (lg)
Extra Large (xl)
<x-ui.progress value="65" size="xs" />
<x-ui.progress value="65" size="sm" />
<x-ui.progress value="65" size="md" />
<x-ui.progress value="65" size="lg" />
<x-ui.progress value="65" size="xl" />

Livewire Integration

Bind the progress component to Livewire state using wire:model.live for real-time updates:

Upload Progress: %
<div>
    <x-ui.text>Upload Progress: {{ $uploadProgress }}%</x-ui.text>
    <x-ui.progress wire:model.live="uploadProgress" />
    
    <x-ui.button wire:click="simulateUpload">
        Start Upload
    </x-ui.button>
</div>

Alpine.js Integration

Use x-model for client-side reactive progress updates. This works great for pure frontend interactions or in combination with Livewire:

Alpine Progress: %
<div x-data="{ progress: 50 }">

    <x-ui.progress x-model="progress" />

    <x-ui.button x-on:click="progress = Math.min(progress + 10, 100)" size="sm">
        +10%
    </x-ui.button>
    <x-ui.button x-on:click="progress = Math.max(progress - 10, 0)" size="sm" variant="outline">
        -10%
    </x-ui.button>    
    <input type="range" x-model="progress" min="0" max="100" />
</div>

Customizing Bar Color

To use a different color from your theme's primary color, use the [&_[data-slot=bar]] selector with any Tailwind color:

Primary (default)
Red
Amber
Orange
Teal
Rose
Blue
Fuchsia
<!-- Red -->
<x-ui.progress value="70" class="[&_[data-slot=bar]]:bg-red-500" />

<!-- Amber -->
<x-ui.progress value="70" class="[&_[data-slot=bar]]:bg-amber-500" />

Animated Progress

Simulate smooth progress updates using JavaScript's requestAnimationFrame() function for frame-perfect animations:

% Progress
<div 
    x-data="{
        value: 0,
        animate() {
            const duration = 4000;
            const startTime = performance.now();
            
            const updateProgress = (currentTime) => {
                const elapsed = currentTime - startTime;
                const progress = Math.min(elapsed / duration, 1);
                
                this.value = progress * 100;
                
                if (progress < 1) {
                    requestAnimationFrame(updateProgress);
                } else {
                    setTimeout(() => {
                        this.value = 0;
                        this.animate();
                    }, 1000);
                }
            };
            
            requestAnimationFrame(updateProgress);
        }
    }" 
    x-init="animate()"
>
    <x-ui.progress class="[&_[data-slot=bar]]:bg-amber-500" x-model="value" />
</div>

Wave Animation

Add a shimmer wave effect to provide visual feedback during slow or long-running progress updates:

Progress with Wave
Slow Download Simulation
<!-- Wave animation provides visual feedback on slow progress -->
<x-ui.progress class="[&_[data-slot=bar]]:bg-orange-500" value="35" wave />
<x-ui.progress class="[&_[data-slot=bar]]:bg-green-500" value="15" wave size="lg" />

Note: The wave animation uses a white gradient overlay, so it may not be visible on light backgrounds or when using light colors like the default white primary color.

Top and Bottom Slots

Add custom content above or below the progress bar using named slots:

Uploading files...
65%
Processing data
45%
2.4 MB of 5.3 MB
~2 min remaining
<x-ui.progress value="65">
    <x-slot:top>
        <div class="flex justify-between mb-2">
            <x-ui.text>Uploading files...</x-ui.text>
            <x-ui.text>65%</x-ui.text>
        </div>
    </x-slot:top>
    
    <x-slot:bottom>
        <div class="flex justify-between mt-2">
            <x-ui.text size="xs">2.4 MB of 5.3 MB</x-ui.text>
            <x-ui.text size="xs">~2 min remaining</x-ui.text>
        </div>
    </x-slot:bottom>
</x-ui.progress>

Advanced Features

The progress component supports compound state objects for advanced use cases like video buffering and indeterminate loading.

Understanding State Formats

The progress component accepts state in three different formats:

1. Simple Integer (Basic Progress)

public $progress = 50;  // Just a number

2. Compound Object (Advanced Features)

// Value + Buffer (for streaming content)
public $progress = ['value' => 50, 'buffer' => 75];

// Value + Indeterminate (for unknown duration tasks)
public $progress = ['value' => 0, 'indeterminate' => true];

// All properties combined
public $progress = [
    'value' => 50,
    'buffer' => 75,
    'indeterminate' => false
];

State Rules:

  • buffer automatically adjusts to never be less than value
  • When indeterminate: true, the bar displays an animated loading state regardless of value
  • All values are automatically clamped between min and max

Dynamic Color Transitions

Create progress bars that smoothly transition colors based on completion percentage:

% Color transitions from Red → Orange → Yellow → Green
<div 
    x-data="{
        value: 0,
        currentColor: 'rgb(239, 68, 68)',
        getProgressColor() {
            const percent = this.value;
            let r, g, b;
            
            if (percent < 25) {
                const ratio = percent / 25;
                r = 239;
                g = Math.floor(68 + (147 * ratio));
                b = 68;
            } else if (percent < 50) {
                const ratio = (percent - 25) / 25;
                r = Math.floor(239 + (15 * ratio));
                g = Math.floor(215 + (25 * ratio));
                b = Math.floor(68 - (54 * ratio));
            } else if (percent < 75) {
                const ratio = (percent - 50) / 25;
                r = Math.floor(254 - (122 * ratio));
                g = Math.floor(240 - (24 * ratio));
                b = Math.floor(14 + (8 * ratio));
            } else {
                const ratio = (percent - 75) / 25;
                r = Math.floor(132 - (10 * ratio));
                g = Math.floor(216 + (28 * ratio));
                b = Math.floor(22 + (43 * ratio));
            }
            
            return `rgb(${r}, ${g}, ${b})`;
        }
    }"
>
    <x-ui.progress 
        x-model="value"
        x-bind:style="`--color-primary: ${currentColor}`"
        wave
    />
</div>

Note: While color spaces like oklch or HSL provide better color interpolation, I've used RGB here for performance and simplicity in dynamically generating specific color values.

Static Color Switching

Switch between predefined colors based on progress value using Alpine's reactive classes:

Progress: %
<x-ui.progress 
    x-model="progress"
    x-bind:class="{
        '[&_[data-slot=bar]]:bg-red-500': progress < 25,
        '[&_[data-slot=bar]]:bg-orange-500': progress >= 25 && progress < 50,
        '[&_[data-slot=bar]]:bg-yellow-500': progress >= 50 && progress < 75,
        '[&_[data-slot=bar]]:bg-green-500': progress >= 75
    }"
/>

Buffer Progress

Display dual progress bars for buffering scenarios like video players or file downloads. Pass a compound object with both value and buffer properties:

Buffering
Played Position
Buffer Amount
<!-- Alpine.js -->
<div x-data="{ progress: {value: 12, buffer: 34 }}">
    <x-ui.progress x-model="progress" />
</div>

<!-- Livewire -->
<!-- public array $progress = ['value' => 12, 'buffer' => 34] -->
<x-ui.progress wire:model.live="progress" />

How it works: The buffer bar always stays ahead of or equal to the current value. If you try to set the value higher than the buffer, the buffer automatically adjusts upward.

Indeterminate Loading

For tasks with unknown duration, use the indeterminate property to display an animated loading state:

Indeterminate Loading...
<!-- Livewire -->
<!-- public array $progress = ['value' => 0, 'indeterminate' => true] -->
<x-ui.progress wire:model.live="progress" />

<!-- Alpine.js -->
<div x-data="{progress: {value: 0, indeterminate: true}}">
    <x-ui.progress x-model="progress" />
</div>

Complete Example: Video Buffering with Indeterminate Support

This example demonstrates using all compound properties together:

Video Buffering Simulation With Indeterminate Loading Support
Played: % | Buffered: %
Played Position
Buffer Amount
<!-- Livewire -->
<!-- public array $progress = ['value' => 12, 'buffer' => 46, 'indeterminate' => false] -->
<x-ui.progress wire:model.live="progress" />
<x-ui.button wire:click="$toggle('progress.indeterminate')">
    Toggle Indeterminate
</x-ui.button>

<!-- Alpine.js -->
<div x-data="{progress: {value: 12, buffer: 46, indeterminate: false}}">
    <x-ui.progress x-model="progress" />
    <x-ui.button x-on:click="progress.indeterminate = !progress.indeterminate">
        Toggle Indeterminate
    </x-ui.button>
</div>

Component Props

ui.progress

Prop Type Default Description
value number 0 Current progress value (0-100)
max number 100 Maximum value for progress calculation
min number 0 Minimum value for progress calculation
size string 'md' Bar height: 'xs', 'sm', 'md', 'lg', 'xl'
buffer number|null null Buffer progress value for dual progress bars
wave boolean false Enable shimmer wave animation
duration number 300 Transition duration in milliseconds
top slot - Custom content displayed above the progress bar
bottom slot - Custom content displayed below the progress bar

Styling

The progress component provides multiple ways to customize colors:

Using CSS Custom Properties

<!-- Static CSS variable -->
<x-ui.progress 
    value="60"
    style="--color-primary: rgb(59, 130, 246)"
/>

<!-- Dynamic color with Alpine -->
<x-ui.progress 
    x-model="progress"
    x-bind:style="`--color-primary: ${dynamicColor}`"
/>

Using Data-Slot Selector

<!-- Static color -->
<x-ui.progress 
    value="60"
    class="[&_[data-slot=bar]]:bg-purple-500"
/>

<!-- Conditional colors with Alpine -->
<x-ui.progress 
    x-model="progress"
    x-bind:class="{
        '[&_[data-slot=bar]]:bg-red-500': progress < 50,
        '[&_[data-slot=bar]]:bg-green-500': progress >= 50
    }"
/>

© SheafUI Copyright 2024-2026. All rights reserved.